[0] Packages loading

rEDM should be the version 1.2.3

https://cran.r-project.org/src/contrib/Archive/rEDM/

library(mathjaxr)
library(rEDM); packageVersion("rEDM")
We are currently building a new version of rEDM, and a version for python pyEDM. Be on the look out for version 1.0 for rEDM. Updates can be found at https://github.com/SugiharaLab
[1] ‘1.2.3’
library(parallel)
library(doParallel)
Loading required package: foreach
Loading required package: iterators
library(foreach)
library(Kendall)
library(MASS)
library(dplyr)

Attaching package: ‘dplyr’

The following object is masked from ‘package:MASS’:

    select

The following objects are masked from ‘package:stats’:

    filter, lag

The following objects are masked from ‘package:base’:

    intersect, setdiff, setequal, union
library(glmnet)
Loading required package: Matrix
Loaded glmnet 4.1-8
library(ggplot2)
#source("../Demo_MDR_function.R")
source("./Demo_MDR_function2.R") #from 2024/05/07

[1] General functions for ODEs

4th-order explicit Runge-Kutta method with a fixed interval function

rk4 <- function(in_vec, ref_data = NULL, time, h_interval, dim, diff_vec)
{
  #in_vec: the vector with the value at "time"
  #out_vec: the vector with which the updated vector value after one time step is saved
  #time: time value
  #h_interval: time step for discritizing ODE
  #dim: dimension of the ODE
  #diff_vec: function that determines the r.h.s. of the ODE
  
  k1 <- numeric(dim)
  k2 <- numeric(dim)
  k3 <- numeric(dim)
  k4 <- numeric(dim)
  temp_vec <- numeric(dim)
  h_half <- h_interval / 2.0
  t_h <- time + h_half
  
  k1 <- diff_vec(in_vec, ref_data, time, h_interval, dim)  # calculate k1
  temp_vec <- in_vec + h_half * k1
  k2 <- diff_vec(temp_vec, ref_data, t_h, h_interval, dim)  # calculate k2
  temp_vec <- in_vec + h_half * k2
  k3 <- diff_vec(temp_vec, ref_data, t_h, h_interval, dim)  # calculate k3
  temp_vec <- in_vec + h_interval * k3
  k4 <- diff_vec(temp_vec, ref_data, time + h_interval, h_interval, dim)  # calculate k4
  
  temp_vec <- in_vec + (h_interval / 6.0) * (k1 + 2.0 * k2 + 2.0 * k3 + k4)
  temp_vec
}

[2] Model01 setting

Interaction strength estimation for time-discrete model (DE) framework

[2.1] Model equations

2-Host 2-Parasitoid System with natural mortality (i.e., with overlapping generations)

Note: When the natural mortality goes to infinity, the model converges to 2-Host 2-Parasitoid Nicolson-Baily Model

\[ H_{k,t+1} = H_{k,t} + r_k exp[-a_{k}H_{k,t} - c_{1k} P_{1,t} - c_{2k} P_{2, t}] H_{k,t} - (1 - exp[-a_{k}H_{k,t} - c_{1k} P_{1,t} - c_{2k} P_{2,t} - m_{H,k}]) H_{k,t} \quad (k=1,2) \tag{D1} \] It is set as \[ H_{k,t+1} = H_{k,t} + F_{Hk}(H_{1,t}, H_{2,t}, P_{1,t}, P_{2,t}) \]

\[ P_{j,t+1} = P_{j,t} + \sum_{k=1,2} exp(-a_k H_{k,t}) (1 - exp[-c_{1k} P_{1,t} - c_{2k} P_{2,t}]) \frac{c_{jk} P_{j,t}}{c_{1k} P_{1,t} + c_{2k} P_{2,t}} H_{k,t} -(1 - exp(-m_{P,j})) P_{j,t} \quad (j=1,2) \tag{D2} \] It is set as \[ P_{j,t+1} = P_{j,t} + F_{Pj}(H_{1,t}, H_{2,t}, P_{1,t}, P_{2,t}) \]

[2.2] Parameters and settings for the 4-species coupled host-parasitoid model

[2.2.1] Parameter value setting
r1 <- 2.0
r2 <- 2.0
a1 <- 0.1
a2 <- 0.1
c11 <- 0.3 #P1 -> H1
c21 <- 0.1 #P2 -> H1
c12 <- 0.1 #P1 -> H2
c22 <- 0.3 #P2 -> H2
mH1 <- 0.1
mH2 <- 0.1
mP1 <- 0.1
mP2 <- 0.1
[2.2.2] Setting for numerical calculations
j_Host1 <- 1
j_Host2 <- 2
j_Paras1 <- 3
j_Paras2 <- 4
[2.2.3] Functions specific to 4-sp model

Note that FH1, FH2, FP1, FP2, are defined as the changes of the abundance (X_t+1 - X_t)

FH1 <- function(in_vec, t) {
  term1 <- r1*exp(-a1 * in_vec[j_Host1] - c11 * in_vec[j_Paras1] - c21 * in_vec[j_Paras2]) * in_vec[j_Host1]
  term2 <- (1.0 - exp(-a1 * in_vec[j_Host1] - c11 * in_vec[j_Paras1] - c21 * in_vec[j_Paras2] - mH1)) * in_vec[j_Host1]
  return(term1 - term2)
}

FH2 <- function(in_vec, t) {
  term1 <- r2*exp(-a2 * in_vec[j_Host2] - c12 * in_vec[j_Paras1] - c22 * in_vec[j_Paras2]) * in_vec[j_Host2]
  term2 <- (1.0 - exp(-a2 * in_vec[j_Host2] - c12 * in_vec[j_Paras1] - c22 * in_vec[j_Paras2] - mH2)) * in_vec[j_Host2]
  return(term1 - term2)
}
  
FP1 <- function(in_vec, t) {
  term1 <- exp(-a1 * in_vec[j_Host1]) * (1 - exp(-c11 * in_vec[j_Paras1] - c21 * in_vec[j_Paras2])) * c11 * in_vec[j_Paras1] / (c11 * in_vec[j_Paras1] + c21 * in_vec[j_Paras2]) * in_vec[j_Host1]
  
  term2 <- exp(-a2 * in_vec[j_Host2]) * (1 - exp(-c12 * in_vec[j_Paras1] - c22 * in_vec[j_Paras2])) * c12 * in_vec[j_Paras1] / (c12 * in_vec[j_Paras1] + c22 * in_vec[j_Paras2]) * in_vec[j_Host2]
  
  term3 <- (1.0 - exp(- mP1)) * in_vec[j_Paras1]
  return(term1 + term2 - term3)
}
  
FP2 <- function(in_vec, t) {
  term1 <- exp(-a1 * in_vec[j_Host1]) * (1 - exp(-c11 * in_vec[j_Paras1] - c21 * in_vec[j_Paras2])) * c21 * in_vec[j_Paras2] / (c11 * in_vec[j_Paras1] + c21 * in_vec[j_Paras2]) * in_vec[j_Host1]
  
  term2 <- exp(-a2 * in_vec[j_Host2]) * (1 - exp(-c12 * in_vec[j_Paras1] - c22 * in_vec[j_Paras2])) * c22 * in_vec[j_Paras2] / (c12 * in_vec[j_Paras1] + c22 * in_vec[j_Paras2]) * in_vec[j_Host2]
  
  term3 <- (1.0 - exp(- mP2)) * in_vec[j_Paras2]
  return(term1 + term2 - term3)
}

#function to calculate all changes four dimensional
diff_4HP <- function(in_vec, t, dim){
  temp_vec <- numeric(dim)
  temp_vec[j_Host1] <- FH1(in_vec, t)
  temp_vec[j_Host2] <- FH2(in_vec, t)
  temp_vec[j_Paras1] <- FP1(in_vec, t)
  temp_vec[j_Paras2] <- FP2(in_vec, t)
  temp_vec
} 
[2.2.4] Initial setting and conditions
dim_model2 <- 4
nv_4HP0 <- numeric(dim_model2)
nv_4HP <- numeric(dim_model2)

nv_4HP0[j_Host1] <- 1.0
nv_4HP0[j_Host2] <- 1.0
nv_4HP0[j_Paras1] <- 0.1
nv_4HP0[j_Paras2] <- 0.1

[2.3] Solving the model

[2.3.1] Trial with a single Host - single Parasitoid system
t <- 0  # initial condition (initial time, 0)
end_time <- 1000

#Setting initial condition
nv_4HP[j_Host1] <- 1.0
nv_4HP[j_Host2] <- 0.0
nv_4HP[j_Paras1] <- 0.1
nv_4HP[j_Paras2] <- 0.0


# write initial condition
cat(t, nv_4HP, "\n")
0 1 0 0.1 0 
# record the initial condition
HP_result <- data.frame(t = t, H1 = nv_4HP[j_Host1], H2 = nv_4HP[j_Host2], P1 = nv_4HP[j_Paras1], P2 = nv_4HP[j_Paras2])
#For the transient dynamics (RUN BURN)
for(i in 1:end_time){
  nv_4HP <- nv_4HP + diff_4HP(nv_4HP, t, dim_model2)
  t <- t + 1 #update time
  HP_result <- rbind.data.frame(HP_result, c(t, nv_4HP[j_Host1], nv_4HP[j_Host2], nv_4HP[j_Paras1], nv_4HP[j_Paras2]))
}

head(HP_result)

#Trial of the plot
plot(HP_result$t, HP_result$H1, type = "l", ylim = c(0,20))
par(new = T)
plot(HP_result$t, HP_result$P1, type = "l", ylim = c(0,20), col = "red")

[2.3.2] Trial with two pairs of Host - Parasitoid system
t <- 0  # initial condition (initial time, 0)
end_time <- 2000

#Setting initial condition; it is important to start with asymmetric densities to reach quickly the chaotic attractor
nv_4HP[j_Host1] <- 1.0
nv_4HP[j_Host2] <- 0.5
nv_4HP[j_Paras1] <- 0.1
nv_4HP[j_Paras2] <- 0.2


# write initial condition
cat(t, nv_4HP, "\n")
0 1 0.5 0.1 0.2 
# record the initial condition
HP_result <- data.frame(t = t, H1 = nv_4HP[j_Host1], H2 = nv_4HP[j_Host2], P1 = nv_4HP[j_Paras1], P2 = nv_4HP[j_Paras2])
#For the transient dynamics (RUN BURN)
for(i in 1:end_time){
  nv_4HP <- nv_4HP + diff_4HP(nv_4HP, t, dim_model2)
  t <- t + 1 #update time
  HP_result <- rbind.data.frame(HP_result, c(t, nv_4HP[j_Host1], nv_4HP[j_Host2], nv_4HP[j_Paras1], nv_4HP[j_Paras2]))
}

head(HP_result)

#Trial of the plot
plot(HP_result$t, HP_result$H1, type = "l", ylim = c(0,5))
par(new = T)
plot(HP_result$t, HP_result$P1, type = "l", ylim = c(0,5), col = "red")
par(new = T)
plot(HP_result$t, HP_result$H2, type = "l", ylim = c(0,5), lty = "dashed")
par(new = T)
plot(HP_result$t, HP_result$P2, type = "l", ylim = c(0,5), col = "red", lty = "dashed")


DAY = Sys.Date()
saveRDS(HP_result, paste("HP4p_result_", DAY, ".obj", sep = ""))

[3] A simple analysis with multivariate S-map

Based on https://ushio-ecology-blog.blogspot.com/2019/12/20191225blogger0007.html

[3.1] Analysis with standardization

Loading the default data at 2024-07-25 and taking the final 200 data points in the time series

HP_result <- readRDS("HP4p_result_2024-07-25.obj")
HP_result <- HP_result[1801:2000, ]
[3.1.1] Standardization
HP_result.mean <- apply(HP_result[, -1], 2, mean, na.rm = T)  # mean abundance
HP_result.sd <- apply(HP_result[, -1], 2, sd, na.rm = T)      # SD of abundance 

mean_mat <- matrix(HP_result.mean, nrow = nrow(HP_result) , ncol = length(HP_result.mean), byrow = TRUE)
sd_mat <- matrix(HP_result.sd, nrow = nrow(HP_result) , ncol = length(HP_result.mean), byrow = TRUE)

HP_result_s <- (HP_result[, -1] - mean_mat) /sd_mat # Standardized data set
head(HP_result_s)
[3.1.2] Analysis with the standardized time series data
# data block for smap
HP_smap_block_s <- data.frame(H1 = HP_result_s$H1, H2 = HP_result_s$H2, P1 = HP_result_s$P1, P2 = HP_result_s$P2)

# delete a few column
# conducting univariate smap for obtaining the optimal theta
HP_m_smap_res_s <- block_lnlp(HP_smap_block_s, method = "s-map",
                         target_column = j_Host1, 
                         theta = c(0, 1e-04, 3e-04, 0.001, 0.003, 0.01, 0.03, 0.1, 0.3, 0.5, 0.75, 1, 1.5, 2, 3, 4, 6, 8),
                         silent = TRUE)

Plotting the effect of theta

plot(HP_m_smap_res_s$theta, HP_m_smap_res_s$rmse, type = "b")

(HP_opt_theta_s <- HP_m_smap_res_s$theta[which.min(HP_m_smap_res_s$rmse)])
[1] 8

Conducting multivariate smap with the optimal theta

HP_m_smap_res2_s <- block_lnlp(HP_smap_block_s, method = "s-map", 
                              target_column = j_Host1, 
                              theta = HP_opt_theta_s, 
                              silent = TRUE, 
                              save_smap_coefficients = TRUE)
head(as.data.frame(HP_m_smap_res2_s$smap_coefficients[[1]]))
[3.1.3] Plotting the results
final_ID <- 200
delta_11 <- 1
plot(HP_result$t[-final_ID], HP_m_smap_res2_s$smap_coefficients[[1]]$c_1[-final_ID] - delta_11, type = "l", col = 1, ylim = c(-0.9, 1.0), xlab = "time", ylab = "Smap coefficient: X -> Host1", main = "S-map for H1")
par(new = T)
plot(HP_result$t[-final_ID], HP_m_smap_res2_s$smap_coefficients[[1]]$c_2[-final_ID], type = "l", col = "red", ylim = c(-0.9, 1.0), xlab = "", ylab = "")
par(new = T)
plot(HP_result$t[-final_ID], HP_m_smap_res2_s$smap_coefficients[[1]]$c_3[-final_ID], type = "l", col = "blue", ylim = c(-0.9, 1.0), xlab = "", ylab = "")
par(new = T)
plot(HP_result$t[-final_ID], HP_m_smap_res2_s$smap_coefficients[[1]]$c_4[-final_ID], type = "l", col = "green", ylim = c(-0.9, 1.0), xlab = "", ylab = "")

legend("topright", 
          legend = c("S-map from H1 to H1 - delta11", "S-map from H2 to H1", "S-map from P1 to H1", "S-map from P2 to H1"),  
          col = c("black", "red", "blue", "green"), 
          lty = c(1, 1, 1, 1),              
          cex = 0.8)   

[3.1.4] Plotting the results for manuscript (Fig.1)
gg_HP_result00 <- data.frame(time = HP_result$t[-final_ID], smap = HP_m_smap_res2_s$smap_coefficients[[1]]$c_1[-final_ID], type = rep("H1toH1", 199))
gg_HP_result01 <- data.frame(time = HP_result$t[-final_ID], smap = HP_m_smap_res2_s$smap_coefficients[[1]]$c_1[-final_ID] - delta_11, type = rep("H1toH1_adjusted", 199))
gg_HP_result02 <- data.frame(time = HP_result$t[-final_ID], smap = HP_m_smap_res2_s$smap_coefficients[[1]]$c_2[-final_ID], type = rep("H2toH1", 199))
gg_HP_result03 <- data.frame(time = HP_result$t[-final_ID], smap = HP_m_smap_res2_s$smap_coefficients[[1]]$c_3[-final_ID], type = rep("P1toH1", 199))
gg_HP_result04 <- data.frame(time = HP_result$t[-final_ID], smap = HP_m_smap_res2_s$smap_coefficients[[1]]$c_4[-final_ID], type = rep("P2toH1", 199))

gg_HP_result <- rbind.data.frame(gg_HP_result00, gg_HP_result01)
gg_HP_result <- rbind.data.frame(gg_HP_result, gg_HP_result02)
gg_HP_result <- rbind.data.frame(gg_HP_result, gg_HP_result03)
gg_HP_result <- rbind.data.frame(gg_HP_result, gg_HP_result04)


fig1_ggplot <- ggplot(data = gg_HP_result) +
  scale_colour_manual(values = c("black", "#ff4b00","#4dc4ff", "#f6aa00", "#804000")) +
  scale_shape_manual(values = c(1, 15, 16, 17, 5)) +
 geom_line(aes(x = time, y = smap, group = type, color = type)) +
  geom_point(aes(x = time, y = smap, color = type, shape = type), size = 2) +
  xlim(1800, 1999) +  ylim(-0.5, 1.5) + theme_bw() + theme(legend.position = "bottom") + 
  labs(title = "Figure 1: Time evolution of S-map coefficients", x = "time", y = "Unadjusted and Adjusted S-map coefficients") 
plot(fig1_ggplot)
Warning: Removed 4 rows containing missing values or values outside the scale range
(`geom_point()`).
ggsave("fig1_ggplot.pdf", width = 10, height = 5)
Warning: Removed 4 rows containing missing values or values outside the scale range
(`geom_point()`).

[4] MDR S-map for 2host-2parasitoid system

Applying MDR S-map to the 4sp coupled host-parasitoid model

[4.1] Data prearrangement

Read dataset

da.range <- 1801:2000 # Subsample for data analysis
out.sample <- T # T/F for out-of-sample forecast
nout <- 2  # number of out-of-sample

da.name <- '4p_model'
do <- readRDS("HP4p_result_2024-07-25.obj")
dot <- do[da.range, 1] # data time
do <- do[da.range, -1] # subset of data without t
ndo <- nrow(do)
nin <- ndo - nout # library sample size

Standardization

# In-sample
do.mean <- apply(do[1:nin, ], 2, mean, na.rm = T)  # mean abundance in in-sample
do.sd <- apply(do[1:nin, ], 2, sd, na.rm = T)      # SD of abundance in in-sample
d <- do[1:(nin-1), ]                          # In-sample dataset at time t
d_tp1 <- do[2:(nin), ]                        # In-sample dataset at time t+1
ds <- (d - repmat(do.mean, nrow(d), 1))*repmat(do.sd, nrow(d), 1) ^ -1 # Normalized in-sample dataset at time t
ds_tp1 <- (d_tp1 - repmat(do.mean, nrow(d_tp1), 1))*repmat(do.sd, nrow(d_tp1), 1) ^ -1 # Normalized in-sample dataset at time t+1

# Out-sample
if(out.sample & nout != 0){
  d.test <- do[nin:(ndo - 1), ]                 # Out-of-sample dataset at time t 
  dt_tp1 <- do[(nin + 1): ndo, ]                 # Out-of-sample dataset at time t+1
  ds.test <- (d.test - repmat(do.mean, nrow(d.test), 1))*repmat(do.sd, nrow(d.test), 1) ^ -1 # Normalized out-of-sample dataset at time t
  dst_tp1 <- (dt_tp1 - repmat(do.mean, nrow(dt_tp1), 1))*repmat(do.sd, nrow(dt_tp1), 1) ^ -1 # Normalized out-of-sample dataset at time t+1
}else{d.test <- dt_tp1 <- ds.test <- NULL}

# Compiled data at time t 
ds.all <- rbind(ds, ds.test)
head(ds.all)

Initialization of pseudo-random number generator

seed <- 49563
set.seed(seed)

[4.2] Optimal embedding dimension

Find the optimal embedding dimension, based on univariate simplex projection

Emax <- 4 # equal to or smaller than the number of nodes (dimension of the DE system)
cri <- 'rmse' # model selection 
Ed <- NULL
forecast_skill_simplex <- NULL
for(i in 1:ncol(ds)){
  spx.i <- simplex(ds[, i], E = 2:Emax)
  Ed <- c(Ed, spx.i[which.min(spx.i[, cri])[1], 'E'])
  forecast_skill_simplex <- c(forecast_skill_simplex, spx.i[which.min(spx.i[, cri])[1], 'rho'])
}
Ed # The optimal embedding dimension for each variable
[1] 2 3 2 2

Optimal embedding dimension and forecasting skill

Ed
[1] 2 3 2 2
forecast_skill_simplex
[1] 0.9882117 0.9882610 0.9917444 0.9875901

[4.3] CCM analysis

  • Find causal variables by CCM analysis that will be used for multiview embedding.

  • Warning: It is time consuming for calculating the causation for each node

  • CCM causality test for all node pairs (the function was updated at 2024/05/07)

ccm.out <- ccm.fast.demo(ds, Epair = T, cri = cri, Emax = Emax)
variable 1 ccm completed: 4.148 sec
variable 2 ccm completed: 4.128 sec
variable 3 ccm completed: 4.369 sec
variable 4 ccm completed: 4.172 sec
ccm.sig <- ccm.out[['ccm.sig']]
ccm.rho <- ccm.out[['ccm.rho']]
#To avoid overwrite the original files, we save them with different names,identified by date.
DAY = Sys.Date()
saveRDS(ccm.sig, paste('ccm_sig', da.name,'nin', nin, DAY, '.obj', sep = '_'))
saveRDS(ccm.rho, paste('ccm_rho', da.name,'nin', nin, DAY, 'demo.obj', sep = '_'))

Just in case not conducting CCM but just loading the result of CCM at 2024/07/29

DAY = "2024-07-29"
ccm.sig_old <- readRDS(paste('ccm_sig', da.name,'nin', nin, DAY, '.obj', sep = '_')) 
ccm.rho_old <- readRDS(paste('ccm_rho', da.name,'nin', nin, DAY, 'demo.obj', sep = '_'))
ccm.sig
     [,1] [,2] [,3] [,4]
[1,]    1    1    1    1
[2,]    1    1    1    1
[3,]    1    1    1    1
[4,]    1    1    1    1
ccm.rho
          [,1]      [,2]      [,3]      [,4]
[1,] 0.9968866 0.4473342 0.9284430 0.5018034
[2,] 0.3379242 0.9957334 0.5413753 0.8980526
[3,] 0.9220910 0.4914316 0.9979308 0.4655782
[4,] 0.4084419 0.9041382 0.3693686 0.9952968

[4.4] Multiview distance

[4.4.1] Performing multiview analysis

Based on the causal variables detected in CCM,

  1. generates the time lag series (with maximum lag = 3),

  2. conduct multivariate simplex projection and evaluate the forecast skill, and

  3. selected the best kn(=100) SSR.

Perform multiview embedding analysis for each node

Warning: It is time consuming for running multiview embedding for each nodes

esele_lag <- esim.lag.demo(ds, ccm.rho, ccm.sig, Ed, kmax = 10000, kn = 100, max_lag = 3, Emax = Emax)
sample 1 complete, 37.721 sec 
sample 2 complete, 38.177 sec 
sample 3 complete, 38.148 sec 
sample 4 complete, 37.716 sec 
# To avoid overwrite the original files, we save them with different names, 'XXX_NEW'.
DAY = Sys.Date()
saveRDS(esele_lag, paste('eseleLag', da.name, 'nin', nin, DAY, 'demo.obj', sep='_'))

The list of the selected best multivariate SSRs for each node (species, sp) with

  1. the correlation coefficient (rho)

  2. the list of variables (X_1, X_2, …) used in each SSR, noting that the number of variables is identical to the optimal embedding dimension obtained in [2.1], and

  3. the list of time lags (vlag_1, vlag_2, …) used in the corresponding variables (X_1, X_2, …).

as.data.frame(esele_lag)
[4.4.2] Compute multiview distance
dmatrix.mv <- mvdist.demo(ds, ds.all, esele_lag)
dmatrix.train.mvx <- dmatrix.mv[['dmatrix.train.mvx']]
dmatrix.test.mvx <- dmatrix.mv[['dmatrix.test.mvx']]

Leave-one-out cross-validation for finding the optimal parameters for MDR S-map analysis

–Warning: The cross-validation is the most time-consuming step in MDR S-map requiring massive computations and . Thus, we recommend dividing job into smaller parts (sub.da>1) or used parallel computation (parall=T, ncore>=1)

do.MDR.CV <- T
### The parameter cv.unit determines the precision of selected parameters and strongly influences computation time.
### In our cases, we used cv.unit=0.025 to obtain more precise estimations
### This parameter may be adjusted to 0.05 or even 0.1, depending on how sensitive the results to parameter precision. 
cv.unit <- 0.025
alpha.so <- seq(0, 1, cv.unit);            # Sequence of alpha
sub.da <- 1                                # Divide the computation job into five parts 
afsp <- eqsplit(1:length(alpha.so), sub.da) # Divide the parameter space based on alpha parameter
alf <- 1                                   # Run CV in the first parameter subset 

# Cross-validation of MDR analysis    
if(do.MDR.CV){
  alpha.s <- alpha.so[afsp[alf, 1]:afsp[alf, 2]] # Subset parameter space
  cv.ind <- cv.MDR.demo(ds, ds_tp1, dmatrix.list = dmatrix.train.mvx, 
                        parall = T, ncore = 24, keep_intra = T,alpha.seq = alpha.s)
  # To avoid overwrite the original files, we save them with different names, 'XXX_NEW'.
  saveRDS(cv.ind, paste(da.name, 'nin', nin, 'cvunit', cv.unit, 'alph', alpha.s[1]*100, DAY, 'cvout_Nmvx_Rallx.obj', sep = '_'))
}
[4.4.3] Selecting the optimal parameters

Select the optimal parameter set for regularized regression model with the minimal MSE

paracv.demo <- secv.demo(cv.ind)
paracv.demo

[4.5] MDR S-map

Fitting MDR S-map based on the parameters selected by CV

Note that the linear regression model in MDR S-map includes all of variables as X even if some of them were not selected as the causal variables at the step of using CCM. This is reasonable because S-map coefficients represent the effects of variables at short timescale while CCM evaluates the causality in the whole period of the time series.

#Setting
do.MDR <- F
cv.unit <- 0.025                           
ptype <- 'aenet'          #enet:elastic-net or msaenet: adaptive elastic-net

#Fitting the MDR S-map
smap.2H2P <- MDRsmap.demo(paracv = paracv.demo, ptype = ptype, keep_intra = T, out.sample = T,
                            ds,ds_tp1,ds.test,dst_tp1,
                            dmatrix.list = dmatrix.train.mvx,
                            dmatrix.test.list = dmatrix.test.mvx)

In case for saving the results

DAY = Sys.Date()
nr.out <- smap.2H2P[['nr.out']];

  saveRDS(nr.out, paste(da.name,'_nin', nin, 'cvunit', cv.unit, ptype, DAY, 'nrout_Nmvx_Rallx_demo_NEW.obj',sep = '_'))
    # Save interaction Jacobian matrices at all time points
  saveRDS(smap.2H2P[['jcof']], paste(da.name,'nin', nin, 'cvunit', cv.unit, ptype, DAY, '_jcof_Nmvx_Rallx_demo_NEW.obj', sep='_'))

S-map coefficients

smap.2H2P[['jcof']]

[4.6] Compare S-map coefficients and theoretical benchmark

Loading data

smap.2H2P <- list()
smap.2H2P[['jcof']] <- readRDS("4p_model_nin_198_cvunit_0.025_aenet_2024-07-31__jcof_Nmvx_Rallx_demo_NEW.obj")
smap.2H2P[['jcof']]
[4.6.1] Compare multivariate S-map and MDR S-map
final_ID <- 200
delta_11 <- 1

MDR_Smap_dH1dH1 <- subset(smap.2H2P[['jcof']], variable == j_Host1)[1:199, 5] - delta_11
MDR_Smap_dH1dH2 <- subset(smap.2H2P[['jcof']], variable == j_Host1)[1:199, 6]
MDR_Smap_dH1dP1 <- subset(smap.2H2P[['jcof']], variable == j_Host1)[1:199, 7]
MDR_Smap_dH1dP2 <- subset(smap.2H2P[['jcof']], variable == j_Host1)[1:199, 8]

plot(HP_result$t[-final_ID], HP_m_smap_res2_s$smap_coefficients[[1]]$c_1[-final_ID] - delta_11, type = "l", col = 1, ylim = c(-0.9, 1.0), xlab = "time", ylab = "Interation coefficients")
par(new = T)
plot(HP_result$t[-final_ID], HP_m_smap_res2_s$smap_coefficients[[1]]$c_2[-final_ID], type = "l", col = "red", ylim = c(-0.9, 1.0), xlab = "", ylab = "")
par(new = T)
plot(HP_result$t[-final_ID], HP_m_smap_res2_s$smap_coefficients[[1]]$c_3[-final_ID], type = "l", col = "blue", ylim = c(-0.9, 1.0), xlab = "", ylab = "")
par(new = T)
plot(HP_result$t[-final_ID], HP_m_smap_res2_s$smap_coefficients[[1]]$c_4[-final_ID], type = "l", col = "green", ylim = c(-0.9, 1.0), xlab = "", ylab = "")
par(new = T)
plot(HP_result$t[-final_ID], MDR_Smap_dH1dH1, type = "l", col = "brown", ylim = c(-0.9, 1.0), xlab = "", ylab = "")
par(new = T)
plot(HP_result$t[-final_ID], MDR_Smap_dH1dP1, type = "l", col = "cyan", ylim = c(-0.9, 1.0), xlab = "", ylab = "")

legend("topright", 
          legend = c("S-map from H1 to H1 - delta11", "S-map from H2 to H1", "S-map from P1 to H1", "S-map from P2 to H1","MDR S-map from H1 to H1 - delta11", "MDR S-map from P1 to H1"),  
          col = c("black", "red", "blue", "green", "brown", "cyan"), 
          lty = c(1, 1, 1, 1, 1, 1),              
          cex = 0.8)   

[4.6.2] List of theoretical Jacobian

\[ \frac{\partial F_{H,i}}{\partial H_{i,k}} = -1 + (1 - a_i H_i) e ^ {-a_i H_i - c_{1i} P_1 - c_{2i} P_2} (r_i + e ^{-m_{H,i}}) \] \[ \frac{\partial F_{H,i}}{\partial H_{i',k}} = 0 \] \[ \frac{\partial F_{H,i}}{\partial P_{j,k}} = c_{ji} e ^ {-a_i H_i - c_{1i} P_1 - c_{2i} P_2} (-r_i - e ^ {-m_{H,i}}) H_k \]

Functions for partial derivatives for H1:

dF_H1dH1 <- function(data) {
  coeff <- -1 + (1 - a1 * data$H1) * exp(- a1 * data$H1 - c11 * data$P1 - c21 * data$P2) * (r1 + exp(- mH1))
  
  return(coeff)
}

dF_H1dP1 <- function(data) {
  coeff <- c11 * exp(- a1 * data$H1 - c11 * data$P1 - c21 * data$P2) * (- r1 - exp(- mH1)) * data$H1
  
  return(coeff)
}  

dF_H1dP2 <- function(data) {
  coeff <- c21 * exp(- a1 * data$H1 - c11 * data$P1 - c21 * data$P2) * (- r1 - exp(- mH1)) * data$H1
  
  return(coeff)
}
[4.6.3] Comparison for the diagonal element (Fig. 2ab: H1 -> H1): ggplot

Dataframe for ggplot

#For lineplots
H2P2_H1toH1_ggplot <- data.frame(
  time = HP_result$t[-final_ID],
  IntS = HP_m_smap_res2_s$smap_coefficients[[1]]$c_1[-final_ID] - delta_11,
  type = rep("01std_smapH1toH1", 199)
)
H2P2_H1toH1_ggplot <- rbind.data.frame(
  H2P2_H1toH1_ggplot, data.frame(
    time = HP_result$t[-final_ID],
    IntS = MDR_Smap_dH1dH1,
    type = rep("02mdr_smapH1toH1", 199)
  )
)
H2P2_H1toH1_ggplot <- rbind.data.frame(
  H2P2_H1toH1_ggplot, data.frame(
    time = HP_result$t[-final_ID],
    IntS = dF_H1dH1(HP_result)[-final_ID],
    type = rep("03IS_dH1dH1", 199)
  )
)
                                
H2P2_P1toH1_ggplot <- data.frame(
  time = HP_result$t[-final_ID],
  IntS = HP_m_smap_res2_s$smap_coefficients[[1]]$c_3[-final_ID],
  type = rep("01std_smapP1toH1", 199)
)
H2P2_P1toH1_ggplot <- rbind.data.frame(
  H2P2_P1toH1_ggplot, data.frame(
    time = HP_result$t[-final_ID],
    IntS = MDR_Smap_dH1dP1,
    type = rep("02mdr_smapP1toH1", 199)
  )
)
H2P2_P1toH1_ggplot <- rbind.data.frame(
  H2P2_P1toH1_ggplot, data.frame(
    time = HP_result$t[-final_ID],
    IntS = dF_H1dP1(HP_result)[-final_ID] * HP_result.sd[3] / HP_result.sd[1],
    type = rep("03IS_dH1dP1", 199)
  )
)


#For error plots
H2P2_error_H1toH1_ggplot <- data.frame(
  time = HP_result$t[-final_ID],
  IntS = HP_m_smap_res2_s$smap_coefficients[[1]]$c_1[-final_ID] - delta_11 - dF_H1dH1(HP_result)[-final_ID],
  type = rep("01std_smapH1toH1", 199)
)
H2P2_error_H1toH1_ggplot <- rbind.data.frame(
  H2P2_error_H1toH1_ggplot, data.frame(
    time = HP_result$t[-final_ID],
    IntS = MDR_Smap_dH1dH1 - dF_H1dH1(HP_result)[-final_ID],
    type = rep("02mdr_smapH1toH1", 199)
  )
)

H2P2_error_P1toH1_ggplot <- data.frame(
  time = HP_result$t[-final_ID],
  IntS = HP_m_smap_res2_s$smap_coefficients[[1]]$c_3[-final_ID] - dF_H1dP1(HP_result)[-final_ID] * HP_result.sd[3] / HP_result.sd[1],
  type = rep("01std_smapP1toH1", 199)
)
H2P2_error_P1toH1_ggplot <- rbind.data.frame(
  H2P2_error_P1toH1_ggplot, data.frame(
    time = HP_result$t[-final_ID],
    IntS = MDR_Smap_dH1dP1 - dF_H1dP1(HP_result)[-final_ID] * HP_result.sd[3] / HP_result.sd[1],
    type = rep("02mdr_smapP1toH1", 199)
  )
)
fig2a_ggplot <- ggplot(data = H2P2_H1toH1_ggplot) +
  scale_colour_manual(values = c("#ff4b00", "#4dc4ff", "#f6aa00")) +
  scale_shape_manual(values = c(15, 16, 17)) +
 geom_line(aes(x = time, y = IntS, group = type, color = type)) +
  geom_point(aes(x = time, y = IntS, color = type, shape = type), size = 2) +
  xlim(1800, 1999) + theme_bw() + theme(legend.position = "bottom") +  
  labs(title = "Figure 2a: Time evolution of H1 -> H1", x = "time", y = "H1 -> H1") 

fig2b_ggplot <- ggplot(H2P2_error_H1toH1_ggplot, aes(type, abs(IntS))) +
    scale_colour_manual(values = c("#ff4b00", "#4dc4ff", "#f6aa00")) +
    scale_shape_manual(values = c(15, 16, 17)) +
    geom_boxplot(outlier.shape = NA) +
    geom_jitter(aes(shape = type, color = type, alpha = 0.1), width = 0.25, size = 3) +
    theme_bw() + theme(legend.position = "bottom") + 
    labs (title = "Figure 2b: Comparison to parametric IS: H1 -> H1") 

plot(fig2a_ggplot)
ggsave("fig2a.pdf", width = 6, height = 4)

plot(fig2b_ggplot)
ggsave("fig2b.pdf", width = 4, height = 4)

[4.6.4] Comparison for the off-diagonal element (Fig. 2cd: P1 -> H1): ggplot
fig2c_ggplot <- ggplot(data = H2P2_P1toH1_ggplot) +
  scale_colour_manual(values = c("#ff4b00", "#4dc4ff", "#f6aa00")) +
  scale_shape_manual(values = c(15, 16, 17)) +
 geom_line(aes(x = time, y = IntS, group = type, color = type)) +
  geom_point(aes(x = time, y = IntS, color = type, shape = type), size = 2) +
  xlim(1800, 1999) + theme_bw() + theme(legend.position = "bottom") +   
  labs(title = "Figure 2c: Time evolution of P1 -> H1", x = "time", y = "P1 -> H1") 

fig2d_ggplot <- ggplot(H2P2_error_P1toH1_ggplot, aes(type, abs(IntS))) +
    scale_colour_manual(values = c("#ff4b00", "#4dc4ff", "#f6aa00")) +
    scale_shape_manual(values = c(15, 16, 17)) +
    geom_boxplot(outlier.shape = NA) +
    geom_jitter(aes(shape = type, color = type, alpha = 0.1), width = 0.25, size = 3) +
    theme_bw() + theme(legend.position = "bottom") +  
    labs (title = "Figure 2d: Comparison to parametric IS: P1 -> H1") 

plot(fig2c_ggplot)
ggsave("fig2c.pdf", width = 6, height = 4)

plot(fig2d_ggplot)
ggsave("fig2d.pdf", width = 4, height = 4)

[4.6.5] Comparison for both diagonal and off-diagonal by correlation/regression
#for diagonal element (H1 -> H1)
plot(dF_H1dH1(HP_result)[-final_ID], HP_m_smap_res2_s$smap_coefficients[[1]]$c_1[-final_ID] - delta_11, 
     xlab = "theoretical coefficient (H1 -> H1)",
     ylab = "standard S-map coefficient (H1 -> H1)",
     )
abline(coef = c(0,1))


cor(dF_H1dH1(HP_result)[-final_ID], HP_m_smap_res2_s$smap_coefficients[[1]]$c_1[-final_ID] - delta_11)
[1] 0.9781177
#Y should be the theoretical coefficient
x <- HP_m_smap_res2_s$smap_coefficients[[1]]$c_1[-final_ID] - delta_11
summary(lm(dF_H1dH1(HP_result)[-final_ID] ~ x))

Call:
lm(formula = dF_H1dH1(HP_result)[-final_ID] ~ x)

Residuals:
      Min        1Q    Median        3Q       Max 
-0.082187 -0.024128  0.001541  0.023675  0.097218 

Coefficients:
             Estimate Std. Error t value Pr(>|t|)    
(Intercept) -0.001131   0.002422  -0.467    0.641    
x            1.047491   0.015874  65.986   <2e-16 ***
---
Signif. codes:  0 ‘***’ 0.001 ‘**’ 0.01 ‘*’ 0.05 ‘.’ 0.1 ‘ ’ 1

Residual standard error: 0.03386 on 197 degrees of freedom
Multiple R-squared:  0.9567,    Adjusted R-squared:  0.9565 
F-statistic:  4354 on 1 and 197 DF,  p-value: < 2.2e-16
plot(dF_H1dH1(HP_result)[-final_ID], MDR_Smap_dH1dH1,
     xlab = "theoretical coefficient (H1 -> H1)",
     ylab = "MDR S-map coefficient (H1 -> H1)"
     )
abline(coef = c(0,1))


cor(dF_H1dH1(HP_result)[-final_ID], MDR_Smap_dH1dH1)
[1] 0.6705204
summary(lm(dF_H1dH1(HP_result)[-final_ID] ~ MDR_Smap_dH1dH1))

Call:
lm(formula = dF_H1dH1(HP_result)[-final_ID] ~ MDR_Smap_dH1dH1)

Residuals:
     Min       1Q   Median       3Q      Max 
-0.32306 -0.07849 -0.01325  0.07168  0.33871 

Coefficients:
                Estimate Std. Error t value Pr(>|t|)    
(Intercept)     0.040208   0.009882   4.069 6.83e-05 ***
MDR_Smap_dH1dH1 1.832602   0.144465  12.685  < 2e-16 ***
---
Signif. codes:  0 ‘***’ 0.001 ‘**’ 0.01 ‘*’ 0.05 ‘.’ 0.1 ‘ ’ 1

Residual standard error: 0.1208 on 197 degrees of freedom
Multiple R-squared:  0.4496,    Adjusted R-squared:  0.4468 
F-statistic: 160.9 on 1 and 197 DF,  p-value: < 2.2e-16
#for off-diagonal element (P1 -> H1)
plot(dF_H1dP1(HP_result)[-final_ID] * HP_result.sd[3] / HP_result.sd[1], HP_m_smap_res2_s$smap_coefficients[[1]]$c_3[-final_ID],
     xlab = "theoreticalcoefficient (P1 -> H1)",
     ylab = "standard S-map coefficient (P1 -> H1)"
     )
abline(coef = c(0,1))


cor(dF_H1dP1(HP_result)[-final_ID] * HP_result.sd[3] / HP_result.sd[1], HP_m_smap_res2_s$smap_coefficients[[1]]$c_3[-final_ID])
[1] 0.9619422
y <- dF_H1dP1(HP_result)[-final_ID] * HP_result.sd[3] / HP_result.sd[1]
summary(lm(y ~ HP_m_smap_res2_s$smap_coefficients[[1]]$c_3[-final_ID]))

Call:
lm(formula = y ~ HP_m_smap_res2_s$smap_coefficients[[1]]$c_3[-final_ID])

Residuals:
      Min        1Q    Median        3Q       Max 
-0.116567 -0.021643  0.001839  0.021454  0.109281 

Coefficients:
                                                        Estimate Std. Error t value
(Intercept)                                            -0.007259   0.005382  -1.349
HP_m_smap_res2_s$smap_coefficients[[1]]$c_3[-final_ID]  1.014493   0.020532  49.410
                                                       Pr(>|t|)    
(Intercept)                                               0.179    
HP_m_smap_res2_s$smap_coefficients[[1]]$c_3[-final_ID]   <2e-16 ***
---
Signif. codes:  0 ‘***’ 0.001 ‘**’ 0.01 ‘*’ 0.05 ‘.’ 0.1 ‘ ’ 1

Residual standard error: 0.03924 on 197 degrees of freedom
Multiple R-squared:  0.9253,    Adjusted R-squared:  0.925 
F-statistic:  2441 on 1 and 197 DF,  p-value: < 2.2e-16
plot(dF_H1dP1(HP_result)[-final_ID] * HP_result.sd[3] / HP_result.sd[1], MDR_Smap_dH1dP1,
     xlab = "theoreticalcoefficient (P1 -> H1)",
     ylab = "MDR S-map coefficient (P1 -> H1)"
     )
abline(coef = c(0,1))


cor(MDR_Smap_dH1dP1, dF_H1dP1(HP_result)[-final_ID] * HP_result.sd[3] / HP_result.sd[1])
[1] 0.9709203
summary(lm(y ~ MDR_Smap_dH1dP1))

Call:
lm(formula = y ~ MDR_Smap_dH1dP1)

Residuals:
      Min        1Q    Median        3Q       Max 
-0.122178 -0.017208  0.004087  0.022169  0.071996 

Coefficients:
                Estimate Std. Error t value Pr(>|t|)    
(Intercept)     0.049246   0.005555   8.864  4.6e-16 ***
MDR_Smap_dH1dP1 1.368911   0.024048  56.923  < 2e-16 ***
---
Signif. codes:  0 ‘***’ 0.001 ‘**’ 0.01 ‘*’ 0.05 ‘.’ 0.1 ‘ ’ 1

Residual standard error: 0.03438 on 197 degrees of freedom
Multiple R-squared:  0.9427,    Adjusted R-squared:  0.9424 
F-statistic:  3240 on 1 and 197 DF,  p-value: < 2.2e-16
                                                                

[5] Model02 setting

[5.1] Model equations for the 5-species coupled food chain ODE model

\[ \frac{dP_i}{dt} = v_i \lambda_i \frac{P_i C_i}{C_i + C_i^*} - v_i P_i, \quad (i=1,2) \tag{1} \]

\[ \frac{dC_i}{dt} = \mu_i \kappa_i \frac{C_i R}{R + R^*} - v_i \lambda_i \frac{P_i C_i}{C_i + C_i^*} - \mu_i C_i, \quad (i=1,2) \tag{2} \]

\[ \frac{dR}{dt} = R \left( 1 - \frac{R}{k} \right) - \sum_{i=1,2} \mu_i \kappa_i \frac{C_iR}{R + R^*}.\tag{3} \]

[5.2] Parameters and settings for the 5-species coupled food chain ODE model

[5.2.1] Parameter value setting
v1 <- 0.1
v2 <- 0.07
lambd1 <- 3.2
lambd2 <- 2.9
Cstar1 <- 0.5
Cstar2 <- 0.5
myu1 <- 0.15
myu2 <- 0.15
kp1 <- 2.5
kp2 <- 2.0
Rstar <- 0.3
k <- 1.2
[5.2.2] Settings for numerically solving ODEs
j_P1 <- 1
j_P2 <- 2
j_C1 <- 3
j_C2 <- 4
j_R <- 5
[5.2.3] Functions specific to the 5-sp model
dP1dt <- function(in_vec, t)
{
  growth <- v1 * lambd1 * in_vec[j_P1] * in_vec[j_C1] / (in_vec[j_C1] + Cstar1)
  mortality <- v1 * in_vec[j_P1]
  return(growth - mortality)
}

dP2dt <- function(in_vec, t)
{
  growth <- v2 * lambd2 * in_vec[j_P2] * in_vec[j_C2] / (in_vec[j_C2] + Cstar2)
  mortality <- v2 * in_vec[j_P2]
  return(growth - mortality)
}

dC1dt <- function(in_vec, t)
{
  growth <- myu1 * kp1 * in_vec[j_C1] * in_vec[j_R] / (in_vec[j_R] + Rstar)
  mortality <- v1 * lambd1 * in_vec[j_P1] * in_vec[j_C1] / (in_vec[j_C1] + Cstar1) + myu1 * in_vec[j_C1]
  return(growth - mortality)
}

dC2dt <- function(in_vec, t)
{
  growth <- myu2 * kp2 * in_vec[j_C2] * in_vec[j_R] / (in_vec[j_R] + Rstar)
  mortality  <- v2 * lambd2 * in_vec[j_P2] * in_vec[j_C2] / (in_vec[j_C2] + Cstar2) + myu2 * in_vec[j_C2]
  return(growth - mortality)
}

dRdt <- function(in_vec, t)
{
  growth <- in_vec[j_R] * (1.0 - in_vec[j_R] / k)
  mortality <- myu1 * kp1 * in_vec[j_C1] * in_vec[j_R] / (in_vec[j_R] + Rstar) + myu2 * kp2 * in_vec[j_C2] * in_vec[j_R] / (in_vec[j_R] + Rstar)
  return(growth - mortality)
}

#function to calculate all coefficients, five dimensional
diff_5sp <- function(in_vec, ref_data, t, h_interval, dim){
  temp_vec <- numeric(dim)
  temp_vec[j_P1] <- dP1dt(in_vec, t)
  temp_vec[j_P2] <- dP2dt(in_vec, t)
  temp_vec[j_C1] <- dC1dt(in_vec, t)
  temp_vec[j_C2] <- dC2dt(in_vec, t)
  temp_vec[j_R] <- dRdt(in_vec, t)
  temp_vec
}  
[5.2.4] Initial setting and conditions
dim_model1 <- 5
nv0 <- numeric(dim_model1)
nv <- numeric(dim_model1)

nv0[j_R] <- 1.0
nv0[j_C1] <- 0.5
nv0[j_C2] <- 0.8
nv0[j_P1] <- 0.7
nv0[j_P2] <- 0.8

deltat <- 0.01

[5.3] Solving the model

[5.3.1] Solving the model by the RK4 method
t <- 0.0  # initial condition (initial time, 0)
end_time <- 2000; tau <- 5; transient_period <- 1000
write_index <- 1

#Initial condition set
nv <- nv0 

#write initial condition
cat(t, nv, "\n")
0 0.7 0.8 0.5 0.8 1 
#For the transient dynamics (RUN BURN)
for(i in 1:as.integer(transient_period / deltat)){
  nv <- rk4(in_vec = nv, time = t, h_interval = deltat, dim = dim_model1, diff_vec = diff_5sp)
  t <- t + deltat # update time
}

# record the initial condition after BURNING phase
rk4_result <- data.frame(t = t, P1 = nv[j_P1], P2 = nv[j_P2], C1 = nv[j_C1], C2 = nv[j_C2], R = nv[j_R])

#After transient period
for(i in 1:as.integer((end_time - transient_period) / deltat)){
  nv <- rk4(in_vec = nv, time = t, h_interval = deltat, dim = dim_model1, diff_vec = diff_5sp)
  t <- t + deltat # update time
  ###record the result every "tau only
  if(write_index < as.integer(tau / deltat)){
    write_index <- write_index + 1
  }
  else {
    #cat(time, nv_ee1,"\n")
    rk4_result <- rbind.data.frame(rk4_result, c(t, nv[j_P1], nv[j_P2], nv[j_C1], nv[j_C2], nv[j_R]))
    write_index <- 1
  }
}
head(rk4_result)

saveRDS(rk4_result, "rk4_result_5sp_model.obj")
[5.3.2] Basic plot for the result
plot(rk4_result$t, rk4_result$C1, col = "red", type = "l", xlab = "time", ylab = "abundance", ylim = c(0, 2.0))
par(new = T)
plot(rk4_result$t, rk4_result$C2, col = "blue", type = "l", xlab = "", ylab = "", ylim = c(0, 2.0))
par(new = T)
plot(rk4_result$t, rk4_result$R, col = "green", type = "l", xlab = "", ylab = "", ylim = c(0, 2.0))

[6] Theoretical coefficients evaluated by instantaneous Jacobian

The partial derivative of dC1/dt

with respect to C1: \[ \frac{\partial}{\partial C_{1}} \left( \mu_{1} K_{1} \frac{C_{1} R}{R + R^{*}} - v_{1} \lambda_{1} \frac{P_{1} C_{1}}{C_{1} + C_{1}^{*}} - \mu_{1} C_{1} \right) = K_{1} \mu_{1} \frac{R}{R + R^{*}} - v_{1} \lambda_{1} \frac{P_{1} C_{1}*}{(C_{1} + C_{1}^{*})^2} - \mu_{1} \]

with respect to R: \[ \frac{\partial}{\partial R} \left( \mu_{1} \kappa_{1} \frac{C_{1} R}{R + R^{*}} \right) = \kappa_{1} \mu_{1} \frac{C_{1} R^*}{(R + R^{*})^2} \]

Function definition

dC1dC1 <- function(data) {
  coeff <- myu1 * kp1 * data$R / (data$R + Rstar) - v1 * lambd1 * data$P1 * Cstar1/ (data$C1 + Cstar1)^2 - myu1
  return(coeff)
}
dC1dR <- function(data) {
  coeff <- myu1 * kp1 * data$C1 *Rstar / (data$R + Rstar)^2
  return(coeff)
}

[7] Adjusted interaction strengths with multivariate S-map

Based on https://ushio-ecology-blog.blogspot.com/2019/12/20191225blogger0007.html

[7.1] Analysis with standardization

[7.1.1] Standardization
rk4_result.mean <- apply(rk4_result[, -1], 2, mean, na.rm = T)  # mean abundance
rk4_result.sd <- apply(rk4_result[, -1], 2, sd, na.rm = T)      # SD of abundance 

mean_mat <- matrix(rk4_result.mean, nrow = nrow(rk4_result) , ncol = length(rk4_result.mean), byrow = TRUE)
sd_mat <- matrix(rk4_result.sd, nrow = nrow(rk4_result) , ncol = length(rk4_result.mean), byrow = TRUE)

rk4_result_s <- (rk4_result[, -1] - mean_mat) /sd_mat # Standardized dataset
head(rk4_result_s)
[7.1.2] Analaysis with the standardized time series data
# data block for smap
rk4_smap_block_s <- data.frame(P1 = rk4_result_s$P1, P2 = rk4_result_s$P2, C1 = rk4_result_s$C1, C2 = rk4_result_s$C2, R = rk4_result_s$R)

# delete a few column
#rk4_smap_block_s <- rk4_smap_block_s[, -j_P2] #delete P2 from the embedding

# conducting smap for obtaining the optimal theta
rk4_m_smap_res_s <- block_lnlp(rk4_smap_block_s, method = "s-map",
                         target_column = j_C1, 
                         theta = c(0, 1e-04, 3e-04, 0.001, 0.003, 0.01, 0.03, 0.1, 0.3, 0.5, 0.75, 1, 1.5, 2, 3, 4, 6, 8),
                         silent = TRUE)

Plotting the effect of theta

plot(rk4_m_smap_res_s$theta, rk4_m_smap_res_s$rmse, type = "b")

(rk4_opt_theta_s <- rk4_m_smap_res_s$theta[which.min(rk4_m_smap_res_s$rmse)])
[1] 8

Conducting standard smap with the optimal theta

rk4_m_smap_res2_s <- block_lnlp(rk4_smap_block_s, method = "s-map", 
                              target_column = j_C1, 
                              theta = rk4_opt_theta_s, 
                              silent = TRUE, 
                              save_smap_coefficients = TRUE)
head(as.data.frame(rk4_m_smap_res2_s$smap_coefficients[[1]]))

[7.2] Compare standard S-map and instantaneous interaction strengths (IIS)

final_ID <- 201
plot(rk4_result$t[-final_ID], rk4_m_smap_res2_s$smap_coefficients[[1]]$c_3[-final_ID] - 1.0, type = "l", col = 1, ylim = c(-1, 1), xlab = "time", ylab = "Smap coefficient: C1 -> C1")
par(new = T)
plot(rk4_result$t[-final_ID], tau*dC1dC1(rk4_result)[-final_ID], type = "l", col = "blue", ylim = c(-1, 1), xlab = "", ylab = "")

[8] Deriving mathematically correct interaction coefficients

[8.1] Model setting

[8.1.1] List of partial derivatives (Jacobian)

\[ \frac{\partial F_{P_1}}{\partial P_1} = v_1 \lambda_1 \frac{C_1}{C_1 + C_1^*} - v_1, \frac{\partial F_{P_1}}{\partial P_2} = 0, \frac{\partial F_{P_1}}{\partial C_1} = v_1 \lambda_1 \frac{P_1 C_1^*}{(C_1 + C_1^*)^2}, \frac{\partial F_{P_1}}{\partial C_2} = \frac{\partial F_{P_1}}{\partial R} = 0, \]

\[ \frac{\partial F_{P_2}}{\partial P_1} = 0, \frac{\partial F_{P_2}}{\partial P_2} = v_2 \lambda_2 \frac{C_2}{C_2 + C_2^*} - v_2, \frac{\partial F_{P_2}}{\partial C_1} = 0, \frac{\partial F_{P_2}}{\partial C_2} = v_2 \lambda_2 \frac{P_2 C_2^*}{(C_2 + C_2^*)^2}, \frac{\partial F_{P_2}}{\partial R} = 0, \]

\[ \frac{\partial F_{C_1}}{\partial P_1} = -v_1 \lambda_1 \frac{C_1}{C_1 + C_1^*}, \frac{\partial F_{C_1}}{\partial P_2} = 0, \frac{\partial F_{C_1}}{\partial C_1} = \mu_1 \kappa_1 \frac{R}{R + R^*} - v_1 \lambda_1 \frac{P_1 C_1^*}{(C_1 + C_1^*)^2} - \mu_1, \frac{\partial F_{C_1}}{\partial C_2} = 0, \frac{\partial F_{C_1}}{\partial R} = \mu_1 \kappa_1 \frac{C_1 R^*}{(R + R^*)^2}, \]

\[ \frac{\partial F_{C_2}}{\partial P_1} = 0, \frac{\partial F_{C_2}}{\partial P_2} = -v_2 \lambda_2 \frac{C_2}{C_2 + C_2^*}, \frac{\partial F_{C_2}}{\partial C_1} = 0, \frac{\partial F_{C_2}}{\partial C_2} = \mu_2 \kappa_2 \frac{R}{R + R^*} - v_2 \lambda_2 \frac{P_2 C_2^*}{(C_2 + C_2^*)^2} - \mu_2, \frac{\partial F_{C_2}}{\partial R} = \mu_2 \kappa_2 \frac{C_2 R^*}{(R + R^*)^2}, \]

\[ \frac{\partial F_{R}}{\partial P_1} = \frac{\partial F_{R}}{\partial P_2} = 0, \frac{\partial F_{R}}{\partial C_1} = - \mu_1 \kappa_1 \frac{R}{R + R^*}, \frac{\partial F_{R}}{\partial C_2} = - \mu_2 \kappa_2 \frac{R}{R + R^*}, \frac{\partial F_{R}}{\partial R} = \left( 1 - \frac{2 R}{k} \right)- \sum_{i=1,2} \mu_i \kappa_i \frac{C_i R^*}{(R + R^*)^2}. \]

[8.1.2] Functions specific to the linearized model

Partial derivatives

rF_P1rX <- function(in_vec, t) {
  nv_p <- numeric(length(in_vec))
  
  nv_p[j_P1] <- v1 * lambd1 * in_vec[j_C1] / (in_vec[j_C1] + Cstar1) - v1
  nv_p[j_P2] <- 0
  nv_p[j_C1] <- v1 * lambd1 * in_vec[j_P1] * Cstar1 / (in_vec[j_C1] + Cstar1)^2
  nv_p[j_C2] <- 0
  nv_p[j_R] <- 0
  
  return(nv_p)
}

rF_P2rX <- function(in_vec, t) {
  nv_p <- numeric(length(in_vec))
  
  nv_p[j_P2] <- v2 * lambd2 * in_vec[j_C2] / (in_vec[j_C2] + Cstar2) - v2
  nv_p[j_P1] <- 0
  nv_p[j_C2] <- v2 * lambd2 * in_vec[j_P2] * Cstar2 / (in_vec[j_C2] + Cstar2)^2
  nv_p[j_C1] <- 0
  nv_p[j_R] <- 0
  
  return(nv_p)
}

rF_C1rX <- function(in_vec, t) {
  nv_p <- numeric(length(in_vec))
  
  nv_p[j_P1] <- -v1 * lambd1 * in_vec[j_C1] / (in_vec[j_C1] + Cstar1)
  nv_p[j_P2] <- 0
  nv_p[j_C1] <- myu1 * kp1 * in_vec[j_R] / (in_vec[j_R] + Rstar) - v1 * lambd1 * in_vec[j_P1] * Cstar1/ (in_vec[j_C1] + Cstar1)^2 - myu1
  nv_p[j_C2] <- 0
  nv_p[j_R] <- myu1 * kp1 * in_vec[j_C1] * Rstar / (in_vec[j_R] + Rstar)^2
  
  return(nv_p)
}

rF_C2rX <- function(in_vec, t) {
  nv_p <- numeric(length(in_vec))
  
  nv_p[j_P2] <- -v2 * lambd2 * in_vec[j_C2] / (in_vec[j_C2] + Cstar2)
  nv_p[j_P1] <- 0
  nv_p[j_C2] <- myu2 * kp2 * in_vec[j_R] / (in_vec[j_R] + Rstar) - v2 * lambd2 * in_vec[j_P2] * Cstar2/ (in_vec[j_C2] + Cstar2)^2 - myu2
  nv_p[j_C1] <- 0
  nv_p[j_R] <- myu2 * kp2 * in_vec[j_C2] * Rstar / (in_vec[j_R] + Rstar)^2
  
  return(nv_p)
}

rF_RrX <- function(in_vec, t) {
  nv_p <- numeric(length(in_vec))
  
  nv_p[j_P1] <- 0
  nv_p[j_P1] <- 0
  nv_p[j_C1] <- -myu1 * kp1 * in_vec[j_R] / (in_vec[j_R] + Rstar)
  nv_p[j_C2] <- -myu2 * kp2 * in_vec[j_R] / (in_vec[j_R] + Rstar)
  nv_p[j_R] <- (1 - 2 * in_vec[j_R] / k) - (myu1 * kp1 * in_vec[j_C1] + myu2 * kp2 * in_vec[j_C2]) * Rstar / (in_vec[j_R] + Rstar)^2
  
  return(nv_p)
}

Linearlized perturbed ODE system equations \[ \frac{d\boldsymbol{\delta}(t)}{dt} = \mathbf{J}_{t} \boldsymbol{\delta}(t), \quad \boldsymbol{\delta}(0) = \Delta \boldsymbol{x}_{j}. \tag{7a} \]

\[\begin{align} IC_{i,j,adj}(k=k_1) &= \lim_{\Delta x \to 0} \frac{\left[\phi(\boldsymbol{x}(k_1) + \Delta x_j, \tau) - \phi(\boldsymbol{x}(k_1), \tau)\right]_i}{\Delta x} - \delta_{ij}\\ &= \lim_{\Delta x \to 0} \frac{\left[\boldsymbol{\delta}_n (\tau)\right]_i}{\Delta x} - \delta_{ij} \\ &\approx \frac{\left[\boldsymbol{\delta}_n (\tau)\right]_i}{\Delta x} - \delta_{ij} \tag{7c} \end{align}\]

Linearlized ODE system

dP1Ldt <- function(in_vec, ref_data, t)
{
  ref_vec <- as.numeric(ref_data[t, -1])
  return(as.numeric(rF_P1rX(ref_vec) %*% in_vec))
}

dP2Ldt <- function(in_vec, ref_data, t)
{
  ref_vec <- as.numeric(ref_data[t, -1])
  return(as.numeric(rF_P2rX(ref_vec) %*% in_vec))
}

dC1Ldt <- function(in_vec, ref_data, t)
{
  ref_vec <- as.numeric(ref_data[t, -1])
  return(as.numeric(rF_C1rX(ref_vec) %*% in_vec))
}

dC2Ldt <- function(in_vec, ref_data, t)
{
  ref_vec <- as.numeric(ref_data[t, -1])
  return(as.numeric(rF_C2rX(ref_vec) %*% in_vec))
}

dRLdt <- function(in_vec, ref_data, t)
{
  ref_vec <- as.numeric(ref_data[t, -1])
  return(as.numeric(rF_RrX(ref_vec) %*% in_vec))
}


#function to calculate all coefficients, five dimensional
diff_L_5sp <- function(in_vec, ref_data, t, h_interval, dim){
  temp_vec <- numeric(dim)
  
  t_index <- as.integer((t / h_interval) * 2) #to convert continuous time to the number of row
  
  temp_vec[j_P1] <- dP1Ldt(in_vec, ref_data, t_index)
  temp_vec[j_P2] <- dP2Ldt(in_vec, ref_data, t_index)
  temp_vec[j_C1] <- dC1Ldt(in_vec, ref_data, t_index)
  temp_vec[j_C2] <- dC2Ldt(in_vec, ref_data, t_index)
  temp_vec[j_R] <- dRLdt(in_vec, ref_data, t_index)
  temp_vec
}  

[8.2] Solving the model

[8.2.1] Preparing the fine solution of the ODEs without perturbation

Since rk4() includes the evaluation of derivatives at t + deltat/2, we need to have numerical solutions with the high resolution with deltat/2

t <- 0.0  # initial condition (initial time, 0)
end_time <- 2000; tau <- 5; transient_period <- 1000
write_index <- 1
deltat_fine <- deltat * 0.5

#Initial condition set
nv_rk4_fine <- nv0 

# write initial condition
cat(t, nv_rk4_fine, "\n")
0 0.7 0.8 0.5 0.8 1 
#For the transient dynamics (RUN BURN)
for(i in 1:as.integer(transient_period / deltat_fine)){
  nv_rk4_fine <- rk4(in_vec = nv_rk4_fine, time = t, h_interval = deltat_fine, dim = dim_model1, diff_vec = diff_5sp)
  t <- t + deltat_fine # update time
}

# record the initial condition after BURNING period
rk4_result_fine <- data.frame(t = t, P1 = nv_rk4_fine[j_P1], P2 = nv_rk4_fine[j_P2], C1 = nv_rk4_fine[j_C1], C2 = nv_rk4_fine[j_C2], R = nv_rk4_fine[j_R])

#After transient period
for(i in 1:as.integer((end_time - transient_period) / deltat_fine)){
  nv_rk4_fine <- rk4(in_vec = nv_rk4_fine, time = t, h_interval = deltat_fine, dim = dim_model1, diff_vec = diff_5sp)
  t <- t + deltat_fine # update time
  rk4_result_fine <- rbind.data.frame(rk4_result_fine, c(t, nv_rk4_fine[j_P1], nv_rk4_fine[j_P2], nv_rk4_fine[j_C1], nv_rk4_fine[j_C2], nv_rk4_fine[j_R]))
}

head(rk4_result_fine)
#saveRDS(rk4_result_fine, paste("default", "_rk4_result_fine.obj", sep=""))
#saveRDS(rk4_result_fine, paste(Sys.Date(), "_rk4_result_fine.obj", sep=""))
        

Comparing the solution

plot(rk4_result$t, rk4_result$C1, col = "red", type = "l", xlab = "time", ylab = "abundance", ylim = c(0, 2.0))
par(new = T)
plot(rk4_result_fine$t, rk4_result_fine$C1, col = "black", type = "l", xlab = "", ylab = "", ylim = c(0, 2.0), lty = "dashed")

[8.2.2] Trial for the linearized ODEs for a short time period
#loading the default
rk4_result_fine <- readRDS("default_rk4_result_fine.obj")

delta_x = 0.01 #size of a small perturbation
t <- deltat / 2  # initial condition (initial time, t_abs = transient_period)
t_abs <- t + transient_period - deltat / 2
end_time <- 1.0; tau <- 5;
write_index <- 1

#Initial condition 
nv_linear_p <- c(0, 0, delta_x, 0, 0)
# record the initial condition
result_linear_p <- data.frame(t = t_abs, P1 = nv_linear_p[j_P1], P2 = nv_linear_p[j_P2], C1 = nv_linear_p[j_C1], C2 = nv_linear_p[j_C2], R = nv_linear_p[j_R])
  
for(i in 1:as.integer(end_time / deltat)){
  nv_linear_p <- rk4(in_vec = nv_linear_p, ref_data = rk4_result_fine, time = t, h_interval = deltat, dim = dim_model1, diff_vec = diff_L_5sp)
  t <- t + deltat # update time (starting from the middle)
  t_abs <- t_abs + deltat
  result_linear_p <- rbind.data.frame(result_linear_p, c(t_abs, nv_linear_p[j_P1], nv_linear_p[j_P2], nv_linear_p[j_C1], nv_linear_p[j_C2], nv_linear_p[j_R]))
}
 result_linear_p
NA

The direct evaluation by the nonlinear ODE

t <- 1000 - transient_period + deltat / 2  # initial condition (initial time, t_abs = start_t)
t_index_start <- as.integer((t / deltat) * 2)
t_index_end <- t_index_start + as.integer((1.0 / deltat) * 2)
#Initial condition 
nv_nonlinear_p <- as.numeric(rk4_result_fine[t_index_start, -1]) + c(0, 0, delta_x, 0, 0)

# record the initial condition
result_nonlinear_p <- data.frame(t = t_abs, P1 = nv_nonlinear_p[j_P1], P2 = nv_nonlinear_p[j_P2], C1 = nv_nonlinear_p[j_C1], C2 = nv_nonlinear_p[j_C2], R = nv_nonlinear_p[j_R])
  
for(i in 1:as.integer(end_time / deltat)){
  nv_nonlinear_p <- rk4(in_vec = nv_nonlinear_p, time = t, h_interval = deltat, dim = dim_model1, diff_vec = diff_5sp)
  t <- t + deltat # update time (starting from the middle)
}
 nv_nonlinear_p - as.numeric(rk4_result_fine[t_index_end, -1]) #difference between perturbed and unperturbed solutions
[1]  4.152205e-05 -4.908053e-13  1.139558e-02 -5.768626e-09 -2.217930e-03
[8.2.3] Functions to calculate the interaction strength
#ref_data: the dataset that includes the fine resolution solution of the target nonlinear ODE systems, of which record started at absolute time = transient_period
#deltax: the size of perturbation at t = h_interval/2
#start_t: usually specified as transient_period
#tau: the interval for the calculation
#dim: dimension of ODE system
#diff_vec: the vector field generated by the linearized ODEs with non-perturbed solution
precise_coeff <- function(ref_data, deltax, start_t, tau, h_interval, dim, diff_vec) {
  #matrix to stock results
  nv_linear_p <- matrix(0, nrow = dim, ncol = dim)
  
  #Initial condition 
  nv_linear_p[, j_P1] <- c(deltax, 0, 0, 0, 0)
  nv_linear_p[, j_P2] <- c(0, deltax, 0, 0, 0)
  nv_linear_p[, j_C1] <- c(0, 0, deltax, 0, 0)
  nv_linear_p[, j_C2] <- c(0, 0, 0, deltax, 0)
  nv_linear_p[, j_R] <- c(0, 0, 0, 0, deltax)
  
  tzero <- start_t - transient_period + h_interval / 2  # initial condition (initial time, t_abs = start_t)
  end_time <- tau
  
  for(j in 1:dim) {
    t <- tzero #initialize time for each of different initial perturbations
    for(i in 1:as.integer(end_time / deltat)){
    nv_linear_p[, j] <- rk4(nv_linear_p[, j], ref_data, t, h_interval, dim, diff_vec)
    t <- t + h_interval # update time (starting from the middle)
    }
  }
    
  return(nv_linear_p/deltax)
}

#This is a function that directly used the nonlinear ODE with the perturbed initial conditions
direct_coeff <- function(ref_data, deltax, start_t, tau, h_interval, dim, diff_vec) {
  #matrix to stock results
  nv_nonlinear_p <- matrix(0, nrow = dim, ncol = dim)
  
  tzero <- start_t - transient_period + h_interval / 2  # initial condition (initial time, t_abs = start_t)
  t_index_start <- as.integer((tzero / h_interval) * 2)
  t_index_end <- t_index_start + as.integer((tau / h_interval) * 2)
  #Initial condition 
  nv_nonlinear_p[, j_P1] <- as.numeric(ref_data[t_index_start, -1]) + c(deltax, 0, 0, 0, 0)
  nv_nonlinear_p[, j_P2] <- as.numeric(ref_data[t_index_start, -1]) + c(0, deltax, 0, 0, 0)
  nv_nonlinear_p[, j_C1] <- as.numeric(ref_data[t_index_start, -1]) + c(0, 0, deltax, 0, 0)
  nv_nonlinear_p[, j_C2] <- as.numeric(ref_data[t_index_start, -1]) + c(0, 0, 0, deltax, 0)
  nv_nonlinear_p[, j_R] <- as.numeric(ref_data[t_index_start, -1]) + c(0, 0, 0, 0, deltax)
  
  end_time <- tau
  
 #rk4(in_vec = nv_rk4, time = t, h_interval = deltat, dim = dim_model1, diff_vec = diff_5sp)
  
  for(j in 1:dim) {
    t <- tzero
    for(i in 1:as.integer(end_time / deltat)){
    nv_nonlinear_p[, j] <- rk4(nv_nonlinear_p[, j], ref_data = NULL, t, h_interval, dim, diff_vec)
    t <- t + h_interval # update time (starting from the middle)
    }
  }
  
  #Calculate the difference between the perturbed flow and unperturbed flow
  for(j in 1:dim) nv_nonlinear_p[, j] <- nv_nonlinear_p[, j] - as.numeric(ref_data[t_index_end, -1])  
  
  return(nv_nonlinear_p/deltax)
}
[8.2.4] Linearized model for calculating all points from 1000 to 2000 with interval tau = 5

The reference time points are every tau (= 5.0), but the precise_coeff was calculated for many scenarios (5.0, 0.01, 0.5, 1.0, 2.0, 10.0)

precise_coeff_5sp <- list()
inst_precise_coeff_5sp <- list()
start_time <- vector()

tau <- 5
tau1 <- 5

precise_coeff_5sp <- mclapply(1:200, function(i) {
  start_time[i] <- transient_period + (i - 1)*tau
  result_linear <- precise_coeff(rk4_result_fine, deltax = 0.0001, start_t = start_time[i], tau1, deltat, dim = 5, diff_L_5sp)
  result_linear
}, mc.cores = 16)

tau2 <- 0.01
inst_precise_coeff_5sp <- mclapply(1:200, function(i) {
  start_time[i] <- transient_period + (i - 1)*tau
  result_linear <- precise_coeff(rk4_result_fine, deltax = 0.0001, start_t = start_time[i], tau2, deltat, dim = 5, diff_L_5sp)
  result_linear
}, mc.cores = 16)

tau3 <- 0.5
tau0.5_precise_coeff_5sp <- mclapply(1:200, function(i) {
  start_time[i] <- transient_period + (i - 1)*tau
  result_linear <- precise_coeff(rk4_result_fine, deltax = 0.0001, start_t = start_time[i], tau3, deltat, dim = 5, diff_L_5sp)
  result_linear
}, mc.cores = 16)

tau4 <- 1.0
tau1.0_precise_coeff_5sp <- mclapply(1:200, function(i) {
  start_time[i] <- transient_period + (i - 1)*tau
  result_linear <- precise_coeff(rk4_result_fine, deltax = 0.0001, start_t = start_time[i], tau4, deltat, dim = 5, diff_L_5sp)
  result_linear
}, mc.cores = 16)

tau5 <- 2.0
tau2.0_precise_coeff_5sp <- mclapply(1:200, function(i) {
  start_time[i] <- transient_period + (i - 1)*tau
  result_linear <- precise_coeff(rk4_result_fine, deltax = 0.0001, start_t = start_time[i], tau5, deltat, dim = 5, diff_L_5sp)
  result_linear
}, mc.cores = 16)

tau6 <- 10.0
tau10.0_precise_coeff_5sp <- mclapply(1:200, function(i) {
  start_time[i] <- transient_period + (i - 1)*tau
  result_linear <- precise_coeff(rk4_result_fine, deltax = 0.0001, start_t = start_time[i], tau6, deltat, dim = 5, diff_L_5sp)
  result_linear
}, mc.cores = 16)


precise_coeff_5sp[[5]]
              [,1]          [,2]          [,3]          [,4]         [,5]
[1,]  9.656280e-01  5.598464e-07  2.476259e-01 -0.0185625139 8.142788e-01
[2,]  2.989538e-10  7.047559e-01 -1.358904e-09  0.0001775428 5.175086e-08
[3,] -3.732702e-01  3.687060e-06  2.609733e-01 -0.0990582164 3.229635e+00
[4,]  5.365938e-06 -6.729101e-05 -1.929607e-05  0.6277554416 5.591555e-04
[5,]  2.992122e-01  3.685980e-05 -7.940109e-01 -0.7522821462 1.692837e+01
inst_precise_coeff_5sp[[5]]
              [,1]          [,2]          [,3]          [,4]         [,5]
[1,]  1.000623e+00  4.063713e-18  5.005509e-04 -6.380349e-11 1.479335e-06
[2,]  4.173363e-21  9.993005e-01 -1.026859e-17  6.640377e-07 1.905640e-13
[3,] -1.622704e-03  3.231007e-14  9.981620e-01 -3.814216e-07 5.899615e-03
[4,]  2.510897e-14 -2.537710e-07 -4.635541e-11  9.986299e-01 5.735926e-07
[5,]  1.318010e-07  1.649286e-11 -1.621770e-04 -1.297720e-04 1.003887e+00
tau0.5_precise_coeff_5sp[[5]]
              [,1]          [,2]          [,3]          [,4]         [,5]
[1,]  1.028152e+00  2.811240e-11  2.607848e-02 -8.868742e-06 4.074820e-03
[2,]  2.589855e-14  9.656173e-01 -1.260250e-12  3.102685e-05 4.676182e-10
[3,] -7.628464e-02  3.957674e-09  9.089931e-01 -9.428815e-04 2.912958e-01
[4,]  3.254568e-09 -1.166418e-05 -1.185950e-07  9.343543e-01 2.943598e-05
[5,]  3.857781e-04  4.751814e-08 -9.475474e-03 -7.675132e-03 1.234747e+00
#saveRDS(precise_coeff_5sp, "default_precise_coeff_5sp.obj")
[8.2.5] Nonlinear ODE model for calculating all points from 1000 to 2000 with interval tau = 5
direct_coeff_5sp <- list()

start_time <- vector()
transient_period <- 1000

direct_coeff_5sp <- mclapply(1:200, function(i) {
  start_time[i] <- transient_period + (i - 1)*tau
  result_nonlinear <- direct_coeff(rk4_result_fine, deltax = 0.0001, start_t = start_time[i], tau, deltat, dim = 5, diff_5sp)
  result_nonlinear
}, mc.cores = 16)

direct_coeff_5sp[[5]]
              [,1]          [,2]          [,3]          [,4]         [,5]
[1,]  9.660152e-01  5.557776e-07  2.474247e-01 -0.0185415248 8.139531e-01
[2,]  2.989917e-10  7.047560e-01 -1.357660e-09  0.0001775546 5.174325e-08
[3,] -3.734254e-01  3.671804e-06  2.608073e-01 -0.0990388112 3.230215e+00
[4,]  5.367914e-06 -6.728619e-05 -1.928126e-05  0.6273073468 5.587228e-04
[5,]  2.989064e-01  3.670783e-05 -7.924384e-01 -0.7506920943 1.689479e+01

Comparison between the linearized ODE and nonlinear ODE

(precise_coeff_5sp[[5]] - direct_coeff_5sp[[5]])/direct_coeff_5sp[[5]]
              [,1]          [,2]         [,3]          [,4]          [,5]
[1,] -0.0004007798  7.320764e-03 0.0008132842  0.0011320063  0.0004001401
[2,] -0.0001265475 -3.913425e-08 0.0009166081 -0.0000665089  0.0001469353
[3,] -0.0004155999  4.155022e-03 0.0006365237  0.0001959350 -0.0001795353
[4,] -0.0003679745  7.152273e-05 0.0007680847  0.0007143146  0.0007743651
[5,]  0.0010231664  4.140094e-03 0.0019844202  0.0021181147  0.0019875209

[9] MDR S-map

Applying MDR S-map to the 5sp coupled foodchain model

[9.1] Data prearrangement

Read dataset

da.range <- 1:200 # Subsample for data analysis
out.sample <- T # T/F for out-of-sample forecast
nout <- 2  # number of out-of-sample

da.name <- '5p_model'
do <- readRDS("rk4_result_5sp_model.obj")
dot <- do[da.range, 1] # data time
do <- do[da.range, -1] # subset of data without t
ndo <- nrow(do)
nin <- ndo - nout # library sample size

Standardization

# In-sample
do.mean <- apply(do[1:nin, ], 2, mean, na.rm = T)  # mean abundance in in-sample
do.sd <- apply(do[1:nin, ], 2, sd, na.rm = T)      # SD of abundance in in-sample
d <- do[1:(nin-1), ]                          # In-sample dataset at time t
d_tp1 <- do[2:(nin), ]                        # In-sample dataset at time t+1
ds <- (d - repmat(do.mean, nrow(d), 1))*repmat(do.sd, nrow(d), 1) ^ -1 # Normalized in-sample dataset at time t
ds_tp1 <- (d_tp1 - repmat(do.mean, nrow(d_tp1), 1))*repmat(do.sd, nrow(d_tp1), 1) ^ -1 # Normalized in-sample dataset at time t+1

# Out-sample
if(out.sample & nout != 0){
  d.test <- do[nin:(ndo - 1), ]                 # Out-of-sample dataset at time t 
  dt_tp1 <- do[(nin + 1): ndo, ]                 # Out-of-sample dataset at time t+1
  ds.test <- (d.test - repmat(do.mean, nrow(d.test), 1))*repmat(do.sd, nrow(d.test), 1) ^ -1 # Normalized out-of-sample dataset at time t
  dst_tp1 <- (dt_tp1 - repmat(do.mean, nrow(dt_tp1), 1))*repmat(do.sd, nrow(dt_tp1), 1) ^ -1 # Normalized out-of-sample dataset at time t+1
}else{d.test <- dt_tp1 <- ds.test <- NULL}

# Compiled data at time t 
ds.all <- rbind(ds, ds.test)
head(ds.all)

Initialization of pseudo-random numnber generator

seed <- 49563
set.seed(seed)

[9.2] Optimal embedding dimension

Find the optimal embedding dimension, based on univariate simplex projection

Emax <- 5 # equal to or smaller than the number of nodes (dimension of the ODE system)
cri <- 'rmse' # model selection 
Ed <- NULL
forecast_skill_simplex <- NULL
for(i in 1:ncol(ds)){
  spx.i <- simplex(ds[, i], E = 2:Emax)
  Ed <- c(Ed, spx.i[which.min(spx.i[, cri])[1], 'E'])
  forecast_skill_simplex <- c(forecast_skill_simplex, spx.i[which.min(spx.i[, cri])[1], 'rho'])
}
Ed # The optimal embedding dimension for each variable
[1] 2 3 3 3 2

Optimal embedding dimension and forecasting skill

Ed
[1] 2 3 3 3 2
forecast_skill_simplex
[1] 0.9597235 0.9789125 0.9540209 0.9699363 0.9646669

[9.3] CCM analysis

  • Find causal variables by CCM analysis that will be used for multiview embedding.

  • Warning: It is time consuming for calculating the causation for each node

  • CCM causality test for all node pairs (the function was updated at 2024/05/07)

ccm.out <- ccm.fast.demo(ds, Epair = T, cri = cri, Emax = Emax)
variable 1 ccm completed: 4.655 sec
variable 2 ccm completed: 5.451 sec
variable 3 ccm completed: 7.131 sec
variable 4 ccm completed: 5.187 sec
variable 5 ccm completed: 8.395 sec
ccm.sig <- ccm.out[['ccm.sig']]
ccm.rho <- ccm.out[['ccm.rho']]
#To avoid overwrite the original files, we save them with different names,identified by date.
DAY = Sys.Date()
saveRDS(ccm.sig, paste('ccm_sig', da.name,'nin', nin, DAY, '.obj', sep = '_'))
saveRDS(ccm.rho, paste('ccm_rho', da.name,'nin', nin, DAY, 'demo.obj', sep = '_'))

Just in case not conducting CCM but just loading the result of CCM at 2024/04/27

DAY = "2024-04-27"
#ccm.sig_old <- readRDS(paste('ccm_sig', da.name,'nin', nin, DAY, '.obj', sep = '_')) 
#ccm.rho_old <- readRDS(paste('ccm_rho', da.name,'nin', nin, DAY, 'demo.obj', sep = '_'))
ccm.sig
     [,1] [,2] [,3] [,4] [,5]
[1,]    1    0    1    1    1
[2,]    1    1    1    1    1
[3,]    1    0    1    1    1
[4,]    1    1    1    1    1
[5,]    1    1    1    1    1
#ccm.sig_old
ccm.rho
          [,1]       [,2]      [,3]      [,4]      [,5]
[1,] 0.9926204 0.52102272 0.8795035 0.5119047 0.7022266
[2,] 0.4239670 0.99615225 0.6665958 0.8775080 0.6781655
[3,] 0.3827423 0.05067993 0.9962430 0.4746877 0.7138164
[4,] 0.6730854 0.49475755 0.5352258 0.9986359 0.7918114
[5,] 0.7003931 0.24789633 0.5921757 0.6243611 0.9988016
#ccm.rho_old

[9.4] Multiview distance

[9.4.1] Performing multiview analysis

Based on the causal variables detected in CCM,

  1. generates the time lag series (with maximum lag = 3),

  2. conduct multivariate simplex projection and evaluate the forecast skill, and

  3. selected the best kn(=100) SSR.

Perform multiview embedding analysis for each node

Warning: It is time consuming for running multiview embedding for each nodes

esele_lag <- esim.lag.demo(ds, ccm.rho, ccm.sig, Ed, kmax = 10000, kn = 100, max_lag = 3, Emax = Emax)
# To avoid overwrite the original files, we save them with different names, 'XXX_NEW'.
DAY = Sys.Date()
saveRDS(esele_lag, paste('eseleLag', da.name, 'nin', nin, DAY, 'demo.obj', sep='_'))

The list of the selected best multivariate SSRs for each node (species, sp) with

  1. the correlation coefficient (rho)

  2. the list of variables (X_1, X_2, …) used in each SSR, noting that the number of variables is identical to the optimal embedding dimension obtained in [6.2], and

  3. the list of time lags (vlag_1, vlag_2, …) used in the corresponding variables (X_1, X_2, …).

as.data.frame(esele_lag)
[9.4.2] Compute multiview distance
dmatrix.mv <- mvdist.demo(ds, ds.all, esele_lag)
dmatrix.train.mvx <- dmatrix.mv[['dmatrix.train.mvx']]
dmatrix.test.mvx <- dmatrix.mv[['dmatrix.test.mvx']]

Leave-one-out cross-validation for finding the optimal parameters for MDR S-map analysis

–Warning: The cross-validation is the most time-consuming step in MDR S-map requiring massive computations and . Thus, we recommend dividing job into smaller parts (sub.da>1) or used parallel computation (parall=T, ncore>=1)

do.MDR.CV <- T
### The parameter cv.unit determines the precision of selected parameters and strongly influences computation time.
### In our cases, we used cv.unit=0.025 to obtain more precise estimations
### This parameter may be adjusted to 0.05 or even 0.1, depending on how sensitive the results to parameter precision. 
cv.unit <- 0.025
alpha.so <- seq(0, 1, cv.unit);            # Sequence of alpha
sub.da <- 1                                # Divide the computation job into five parts 
afsp <- eqsplit(1:length(alpha.so), sub.da) # Divide the parameter space based on alpha parameter
alf <- 1                                   # Run CV in the first parameter subset 

# Cross-validation of MDR analysis    
if(do.MDR.CV){
  alpha.s <- alpha.so[afsp[alf, 1]:afsp[alf, 2]] # Subset parameter space
  cv.ind <- cv.MDR.demo(ds, ds_tp1, dmatrix.list = dmatrix.train.mvx, 
                        parall = T, ncore = 24, keep_intra = T, alpha.seq = alpha.s)
  # To avoid overwrite the original files, we save them with different names, 'XXX_NEW'.
  saveRDS(cv.ind, paste(da.name, 'nin', nin, 'cvunit', cv.unit, 'alph', alpha.s[1]*100, DAY, 'cvout_Nmvx_Rallx.obj', sep = '_'))
}
[9.4.3] Selecting the optimal parameters

Select the optimal parameter set for regularized regression model with the minimal MSE

paracv.demo <- secv.demo(cv.ind)
paracv.demo

[9.5] MDR S-map

Fitting MDR S-map based on the parameters selected by CV

Note that the linear regression model in MDR S-map includes all of variables as X even if some of them were not selected as the causal variables at the step of using CCM. This is reasonable because S-map coefficients represent the effects of variables at short timescale while CCM evaluates the causality in the whole period of the time series.

#Setting
do.MDR <- F
cv.unit <- 0.025                           
ptype <- 'aenet'          #enet:elastic-net or msaenet: adaptive elastic-net

#Fitting the MDR S-map
smap.5sp <- MDRsmap.demo(paracv = paracv.demo, ptype = ptype, keep_intra = T, out.sample = T,
                            ds,ds_tp1,ds.test,dst_tp1,
                            dmatrix.list = dmatrix.train.mvx,
                            dmatrix.test.list = dmatrix.test.mvx)

In case for saving the results

DAY = Sys.Date()
nr.out <- smap.5sp[['nr.out']];

  saveRDS(nr.out, paste(da.name,'_nin', nin, 'cvunit', cv.unit, ptype, DAY, 'nrout_Nmvx_Rallx_demo_NEW.obj',sep = '_'))
    # Save interaction Jacobian matrices at all time points
  saveRDS(smap.5sp[['jcof']], paste(da.name,'nin', nin, 'cvunit', cv.unit, ptype, DAY, '_jcof_Nmvx_Rallx_demo_NEW.obj', sep='_'))

S-map coefficients

smap.5sp[['jcof']]
#or
#"5p_model_nin_198_cvunit_0.025_aenet_2024-07-19__jcof_Nmvx_Rallx_demo_NEW.obj"

[10] Comparisons for 5sp model

Loading data

smap.5sp <- list()
smap.5sp[['jcof']] <- readRDS("5p_model_nin_198_cvunit_0.025_aenet_2024-07-19__jcof_Nmvx_Rallx_demo_NEW.obj")
smap.5sp[['jcof']]

[10.1] Compare standard S-map, MDR S-map, IIS, CIS

CRIS (Eqn.21) and direct_IS (Eqn.19)

#normalization by SD
sd_adj_35 <- as.numeric(rk4_result.sd[5] / rk4_result.sd[3])

CRIS_dC1dC1 <- precise_coeff_5sp[[1]][3,3] - 1.0
direct_dC1dC1 <- direct_coeff_5sp[[1]][3,3] - 1.0
CRIS_dC1dR <- sd_adj_35 * precise_coeff_5sp[[1]][3,5]
direct_dC1dR <- sd_adj_35 * direct_coeff_5sp[[1]][3,5]
for(j in 2:200) {
  CRIS_dC1dC1 <- append(CRIS_dC1dC1, precise_coeff_5sp[[j]][3,3] - 1.0)
  direct_dC1dC1 <- append(direct_dC1dC1, direct_coeff_5sp[[j]][3,3] - 1.0)
  CRIS_dC1dR <- append(CRIS_dC1dR, sd_adj_35 * precise_coeff_5sp[[j]][3,5])
  direct_dC1dR <- append(direct_dC1dR, sd_adj_35 * direct_coeff_5sp[[j]][3,5])
}

Dataframe for basic plot

final_ID <- 201
tau <- 5.0
food_chain_result <- data.frame(time = rk4_result$t[-final_ID], std_smapC1toC1 = rk4_m_smap_res2_s$smap_coefficients[[1]]$c_3[-final_ID] - 1.0, std_smapRtoC1 = rk4_m_smap_res2_s$smap_coefficients[[1]]$c_5[-final_ID], mdr_smapC1toC1 = subset(smap.5sp[['jcof']], variable == j_C1)[1:200, 7] - 1.0, mdr_smapRtoC1 = subset(smap.5sp[['jcof']], variable == j_C1)[1:200, 9], IIS_dC1dC1 = tau*dC1dC1(rk4_result)[-final_ID], IIS_dC1dR = tau*dC1dR(rk4_result)[-final_ID], CRIS_dC1dC1, CRIS_dC1dR, direct_dC1dC1, direct_dC1dR)

food_chain_result

Dataframe for ggplot

#For lineplots
rk4_C1toC1_ggplot <- data.frame(
  time = food_chain_result$time,
  IntS = food_chain_result$std_smapC1toC1,
  type = rep("01std_smapC1toC1", 200)
)
rk4_C1toC1_ggplot <- rbind.data.frame(
  rk4_C1toC1_ggplot, data.frame(
    time = food_chain_result$time,
    IntS = food_chain_result$mdr_smapC1toC1,
    type = rep("02mdr_smapC1toC1", 200)
  )
)
rk4_C1toC1_ggplot <- rbind.data.frame(
  rk4_C1toC1_ggplot, data.frame(
    time = food_chain_result$time,
    IntS = food_chain_result$CRIS_dC1dC1,
    type = rep("03CRIS_dC1dC1", 200)
  )
)
rk4_C1toC1_ggplot <- rbind.data.frame(
  rk4_C1toC1_ggplot, data.frame(
    time = food_chain_result$time,
    IntS = food_chain_result$IIS_dC1dC1,
    type = rep("04IIS_dC1dC1", 200)
  )
)                                  

rk4_RtoC1_ggplot <- data.frame(
  time = food_chain_result$time,
  IntS = food_chain_result$std_smapRtoC1,
  type = rep("01std_smapRtoC1", 200)
)
rk4_RtoC1_ggplot <- rbind.data.frame(
  rk4_RtoC1_ggplot, data.frame(
    time = food_chain_result$time,
    IntS = food_chain_result$mdr_smapRtoC1,
    type = rep("02mdr_smapRtoC1", 200)
  )
)
rk4_RtoC1_ggplot <- rbind.data.frame(
  rk4_RtoC1_ggplot, data.frame(
    time = food_chain_result$time,
    IntS = food_chain_result$CRIS_dC1dR,
    type = rep("03CRIS_dC1dR", 200)
  )
)
rk4_RtoC1_ggplot <- rbind.data.frame(
  rk4_RtoC1_ggplot, data.frame(
    time = food_chain_result$time,
    IntS = food_chain_result$IIS_dC1dR,
    type = rep("04IIS_dC1dR", 200)
  )
)

#For error plots
rk4_error_C1toC1_ggplot <- data.frame(
  time = food_chain_result$time,
  IntS = food_chain_result$std_smapC1toC1 - food_chain_result$direct_dC1dC1,
  type = rep("01std_smapC1toC1", 200)
)
rk4_error_C1toC1_ggplot <- rbind.data.frame(
  rk4_error_C1toC1_ggplot, data.frame(
    time = food_chain_result$time,
    IntS = food_chain_result$mdr_smapC1toC1 - food_chain_result$direct_dC1dC1,
    type = rep("02mdr_smapC1toC1", 200)
  )
)
rk4_error_C1toC1_ggplot <- rbind.data.frame(
  rk4_error_C1toC1_ggplot, data.frame(
    time = food_chain_result$time,
    IntS = food_chain_result$CRIS_dC1dC1 - food_chain_result$direct_dC1dC1,
    type = rep("03CRIS_dC1dC1", 200)
  )
)
rk4_error_C1toC1_ggplot <- rbind.data.frame(
  rk4_error_C1toC1_ggplot, data.frame(
    time = food_chain_result$time,
    IntS = food_chain_result$IIS_dC1dC1 - food_chain_result$direct_dC1dC1,
    type = rep("04IIS_dC1dC1", 200)
  )
)

rk4_error_RtoC1_ggplot <- data.frame(
  time = food_chain_result$time,
  IntS = food_chain_result$std_smapRtoC1 - food_chain_result$direct_dC1dR,
  type = rep("01std_smapRtoC1", 200)
)
rk4_error_RtoC1_ggplot <- rbind.data.frame(
  rk4_error_RtoC1_ggplot, data.frame(
    time = food_chain_result$time,
    IntS = food_chain_result$mdr_smapRtoC1 - food_chain_result$direct_dC1dR,
    type = rep("02mdr_smapRtoC1", 200)
  )
)
rk4_error_RtoC1_ggplot <- rbind.data.frame(
  rk4_error_RtoC1_ggplot, data.frame(
    time = food_chain_result$time,
    IntS = food_chain_result$CRIS_dC1dR - food_chain_result$direct_dC1dR,
    type = rep("03CRIS_dC1dR", 200)
  )
)
rk4_error_RtoC1_ggplot <- rbind.data.frame(
  rk4_error_RtoC1_ggplot, data.frame(
    time = food_chain_result$time,
    IntS = food_chain_result$IIS_dC1dR - food_chain_result$direct_dC1dR,
    type = rep("04IIS_dC1dR", 200)
  )
)
[10.1.1] Comparison for the diagonal element (Fig. 3a: C1 -> C1): basic plot
plot(food_chain_result$time, food_chain_result$CRIS_dC1dC1, type = "l", col = "#f6aa00", xlim = c(1400, 1800), ylim = c(-3, 2.0), xlab = "time", ylab = "Smap coefficient: C1 -> C1")
par(new = T)
plot(food_chain_result$time, food_chain_result$std_smapC1toC1, type = "l", col = "#ff4b00", xlim = c(1400, 1800), ylim = c(-3, 2.0), xlab = "", ylab = "")
par(new = T)
plot(food_chain_result$time, food_chain_result$mdr_smapC1toC1, type = "l", col = "#4dc4ff", xlim = c(1400, 1800), ylim = c(-3, 2.0), xlab = "", ylab = "")
par(new = T)
plot(food_chain_result$time, food_chain_result$IIS_dC1dC1, type = "l", lty = "dashed", col = "#804000", xlim = c(1400, 1800), ylim = c(-3, 2.0), xlab = "", ylab = "")

[10.1.2] Comparison for the diagonal element (Fig. 3ab: C1 -> C1): ggplot
fig3a_ggplot <- ggplot(data = rk4_C1toC1_ggplot) +
  scale_colour_manual(values = c("#ff4b00", "#4dc4ff", "#f6aa00", "#804000")) +
  scale_shape_manual(values = c(15, 16, 17, 5)) +
 geom_line(aes(x = time, y = IntS, group = type, color = type)) +
  geom_point(aes(x = time, y = IntS, color = type, shape = type), size = 2) +
  xlim(1400, 1800) + theme_bw() + theme(legend.position = "bottom") +
  labs(title = "Time evolution: C1 -> C1", x = "time", y = "C1 -> C1") 

fig3b_ggplot <- ggplot(rk4_error_C1toC1_ggplot, aes(type, abs(IntS))) +
    scale_colour_manual(values = c("#ff4b00", "#4dc4ff", "#f6aa00", "#804000")) +
    scale_shape_manual(values = c(15, 16, 17, 5)) +
    geom_boxplot(outlier.shape = NA) +
    geom_jitter(aes(shape = type, color = type, alpha = 0.1), width = 0.25, size = 3) +
    theme_bw() + theme(legend.position = "bottom") +
    labs (title = "Comparison to direct_evaluation: C1 -> C1") 

plot(fig3a_ggplot)
ggsave("fig3a.pdf", width = 6, height = 4)

plot(fig3b_ggplot)
ggsave("fig3b.pdf", width = 4, height = 4)

Difference between directly-evaluated CIS and CIS by linearized ODE

summary(abs(food_chain_result$CRIS_dC1dC1 - food_chain_result$direct_dC1dC1))
     Min.   1st Qu.    Median      Mean   3rd Qu.      Max. 
3.157e-06 7.075e-05 2.301e-04 3.547e-04 5.008e-04 1.844e-03 
[10.1.3] Comparison for the diagonal element (Fig. 3cd: R -> C1): ggplot
fig3c_ggplot <- ggplot(data = rk4_RtoC1_ggplot) +
  scale_colour_manual(values = c("#ff4b00", "#4dc4ff", "#f6aa00", "#804000")) +
  scale_shape_manual(values = c(15, 16, 17, 5)) +
 geom_line(aes(x = time, y = IntS, group = type, color = type)) +
  geom_point(aes(x = time, y = IntS, color = type, shape = type), size = 2) +
  xlim(1400, 1800) + theme_bw() + theme(legend.position = "bottom") +
  labs(title = "Time evolution: R -> C1", x = "time", y = "R -> C1") 

fig3d_ggplot <- ggplot(rk4_error_RtoC1_ggplot, aes(type, abs(IntS))) +
    scale_colour_manual(values = c("#ff4b00", "#4dc4ff", "#f6aa00", "#804000")) +
    scale_shape_manual(values = c(15, 16, 17, 5)) +
    geom_boxplot(outlier.shape = NA) +
    geom_jitter(aes(shape = type, color = type, alpha = 0.1), width = 0.25, size = 3) +
    theme_bw() + theme(legend.position = "bottom") +
    labs (title = "Comparison to direct_evaluation: R -> C1") 

plot(fig3c_ggplot)
ggsave("fig3c.pdf", width = 6, height = 4)

plot(fig3d_ggplot)
ggsave("fig3d.pdf", width = 4, height = 4)

Difference between directly-evaluated CIS and CIS by linearized ODE

summary(abs(food_chain_result$CRIS_dC1dR - food_chain_result$direct_dC1dR))
     Min.   1st Qu.    Median      Mean   3rd Qu.      Max. 
5.000e-09 5.918e-06 5.095e-05 5.600e-04 3.540e-04 1.091e-02 
[10.1.4] Comparison for both diagonal and off-diagonal by correlation/regression
#for diagonal element (C1 -> C1)
plot(food_chain_result$std_smapC1toC1 ~ food_chain_result$direct_dC1dC1, 
     xlab = "direct evaluation (C1 -> C1)",
     ylab = "standard S-map coefficient (C1 -> C1)",
     )
abline(coef = c(0,1))


cor(food_chain_result$std_smapC1toC1[-200], food_chain_result$direct_dC1dC1[-200])
[1] 0.8374068
#Y should be the theoretical coefficient
summary(lm(food_chain_result$direct_dC1dC1[-200] ~ food_chain_result$std_smapC1toC1[-200]))

Call:
lm(formula = food_chain_result$direct_dC1dC1[-200] ~ food_chain_result$std_smapC1toC1[-200])

Residuals:
     Min       1Q   Median       3Q      Max 
-1.05026 -0.17010 -0.00113  0.16673  1.45238 

Coefficients:
                                       Estimate Std. Error t value Pr(>|t|)    
(Intercept)                            -0.02650    0.02399  -1.105    0.271    
food_chain_result$std_smapC1toC1[-200]  0.91642    0.04262  21.504   <2e-16 ***
---
Signif. codes:  0 ‘***’ 0.001 ‘**’ 0.01 ‘*’ 0.05 ‘.’ 0.1 ‘ ’ 1

Residual standard error: 0.3337 on 197 degrees of freedom
Multiple R-squared:  0.7013,    Adjusted R-squared:  0.6997 
F-statistic: 462.4 on 1 and 197 DF,  p-value: < 2.2e-16
plot(food_chain_result$mdr_smapC1toC1 ~ food_chain_result$direct_dC1dC1, 
     xlab = "direct evaluation (C1 -> C1)",
     ylab = "MDR S-map coefficient (C1 -> C1)",
     )
abline(coef = c(0,1))


cor(food_chain_result$mdr_smapC1toC1[-200], food_chain_result$direct_dC1dC1[-200])
[1] 0.7521856
#Y should be the theoretical coefficient
summary(lm(food_chain_result$direct_dC1dC1[-200] ~ food_chain_result$mdr_smapC1toC1[-200]))

Call:
lm(formula = food_chain_result$direct_dC1dC1[-200] ~ food_chain_result$mdr_smapC1toC1[-200])

Residuals:
     Min       1Q   Median       3Q      Max 
-1.27802 -0.08214  0.05370  0.19339  0.94716 

Coefficients:
                                       Estimate Std. Error t value Pr(>|t|)    
(Intercept)                            -0.12260    0.03070  -3.994 9.17e-05 ***
food_chain_result$mdr_smapC1toC1[-200]  1.01376    0.06327  16.022  < 2e-16 ***
---
Signif. codes:  0 ‘***’ 0.001 ‘**’ 0.01 ‘*’ 0.05 ‘.’ 0.1 ‘ ’ 1

Residual standard error: 0.4023 on 197 degrees of freedom
Multiple R-squared:  0.5658,    Adjusted R-squared:  0.5636 
F-statistic: 256.7 on 1 and 197 DF,  p-value: < 2.2e-16
plot(food_chain_result$IIS_dC1dC1 ~ food_chain_result$direct_dC1dC1, 
     xlab = "direct evaluation (C1 -> C1)",
     ylab = "instantaneous interaction strength (C1 -> C1)",
     )
abline(coef = c(0,1))


cor(food_chain_result$IIS_dC1dC1[-200], food_chain_result$direct_dC1dC1[-200])
[1] 0.7062711
#Y should be the theoretical coefficient
summary(lm(food_chain_result$direct_dC1dC1[-200] ~ food_chain_result$IIS_dC1dC1[-200]))

Call:
lm(formula = food_chain_result$direct_dC1dC1[-200] ~ food_chain_result$IIS_dC1dC1[-200])

Residuals:
     Min       1Q   Median       3Q      Max 
-1.67035 -0.13355  0.06334  0.30644  1.02468 

Coefficients:
                                   Estimate Std. Error t value Pr(>|t|)    
(Intercept)                        0.005217   0.030881   0.169    0.866    
food_chain_result$IIS_dC1dC1[-200] 0.729854   0.052123  14.003   <2e-16 ***
---
Signif. codes:  0 ‘***’ 0.001 ‘**’ 0.01 ‘*’ 0.05 ‘.’ 0.1 ‘ ’ 1

Residual standard error: 0.4322 on 197 degrees of freedom
Multiple R-squared:  0.4988,    Adjusted R-squared:  0.4963 
F-statistic: 196.1 on 1 and 197 DF,  p-value: < 2.2e-16
#for off-diagonal element (R -> C1)
plot(food_chain_result$std_smapRtoC1 ~ food_chain_result$direct_dC1dR, 
     xlab = "direct evaluation (R -> C1)",
     ylab = "standard S-map coefficient (R -> C1)",
     )
abline(coef = c(0,1))


cor(food_chain_result$std_smapRtoC1[-200], food_chain_result$direct_dC1dR[-200])
[1] 0.5088147
#Y should be the theoretical coefficient
summary(lm(food_chain_result$direct_dC1dR[-200] ~ food_chain_result$std_smapRtoC1[-200]))

Call:
lm(formula = food_chain_result$direct_dC1dR[-200] ~ food_chain_result$std_smapRtoC1[-200])

Residuals:
    Min      1Q  Median      3Q     Max 
-1.3354 -0.2343 -0.1558 -0.0639  4.7867 

Coefficients:
                                      Estimate Std. Error t value Pr(>|t|)    
(Intercept)                            0.11222    0.07033   1.596    0.112    
food_chain_result$std_smapRtoC1[-200]  0.96883    0.11679   8.296 1.68e-14 ***
---
Signif. codes:  0 ‘***’ 0.001 ‘**’ 0.01 ‘*’ 0.05 ‘.’ 0.1 ‘ ’ 1

Residual standard error: 0.7805 on 197 degrees of freedom
Multiple R-squared:  0.2589,    Adjusted R-squared:  0.2551 
F-statistic: 68.82 on 1 and 197 DF,  p-value: 1.678e-14
plot(food_chain_result$mdr_smapRtoC1 ~ food_chain_result$direct_dC1dR, 
     xlab = "direct evaluation (R -> C1)",
     ylab = "MDR S-map coefficient (R -> C1)",
     )
abline(coef = c(0,1))


cor(food_chain_result$mdr_smapRtoC1[-200], food_chain_result$direct_dC1dR[-200])
[1] 0.2223845
#Y should be the theoretical coefficient
summary(lm(food_chain_result$direct_dC1dR[-200] ~ food_chain_result$mdr_smapRtoC1[-200]))

Call:
lm(formula = food_chain_result$direct_dC1dR[-200] ~ food_chain_result$mdr_smapRtoC1[-200])

Residuals:
    Min      1Q  Median      3Q     Max 
-0.6196 -0.4075 -0.2765 -0.0205  5.1085 

Coefficients:
                                      Estimate Std. Error t value Pr(>|t|)   
(Intercept)                            0.22700    0.09899   2.293  0.02290 * 
food_chain_result$mdr_smapRtoC1[-200]  0.59385    0.18549   3.201  0.00159 **
---
Signif. codes:  0 ‘***’ 0.001 ‘**’ 0.01 ‘*’ 0.05 ‘.’ 0.1 ‘ ’ 1

Residual standard error: 0.884 on 197 degrees of freedom
Multiple R-squared:  0.04945,   Adjusted R-squared:  0.04463 
F-statistic: 10.25 on 1 and 197 DF,  p-value: 0.001594
plot(food_chain_result$IIS_dC1dR ~ food_chain_result$direct_dC1dR, 
     xlab = "direct evaluation (R -> C1)",
     ylab = "instantaneous interaction strength (R -> C1)",
     )
abline(coef = c(0,1))


cor(food_chain_result$IIS_dC1dR[-200], food_chain_result$direct_dC1dR[-200])
[1] 0.7100644
#Y should be the theoretical coefficient
summary(lm(food_chain_result$direct_dC1dR[-200] ~ food_chain_result$IIS_dC1dR[-200]))

Call:
lm(formula = food_chain_result$direct_dC1dR[-200] ~ food_chain_result$IIS_dC1dR[-200])

Residuals:
    Min      1Q  Median      3Q     Max 
-2.3629 -0.1519 -0.1442 -0.0614  4.1714 

Coefficients:
                                  Estimate Std. Error t value Pr(>|t|)    
(Intercept)                        0.15031    0.05065   2.967  0.00338 ** 
food_chain_result$IIS_dC1dR[-200]  0.43744    0.03091  14.154  < 2e-16 ***
---
Signif. codes:  0 ‘***’ 0.001 ‘**’ 0.01 ‘*’ 0.05 ‘.’ 0.1 ‘ ’ 1

Residual standard error: 0.6384 on 197 degrees of freedom
Multiple R-squared:  0.5042,    Adjusted R-squared:  0.5017 
F-statistic: 200.3 on 1 and 197 DF,  p-value: < 2.2e-16

[10.2] Compare Instantaneous Jacobian and CIS

Note that:

  1. Precise coeff with very short interval (deltat = 0.01) is identical to instantaneous Jacobian
[10.2.1] For each graph independently
delta_33 <- 1 
precise_data <- data.frame(t = rk4_result$t[1], precise_dC1dC1 = precise_coeff_5sp[[1]][3,3] - delta_33, inst_precise_dC1dC1 = inst_precise_coeff_5sp[[1]][3,3] - delta_33, tau0.5_precise_dC1dC1 = tau0.5_precise_coeff_5sp[[1]][3,3] - delta_33, tau1.0_precise_dC1dC1 = tau1.0_precise_coeff_5sp[[1]][3,3] - delta_33, tau2.0_precise_dC1dC1 = tau2.0_precise_coeff_5sp[[1]][3,3] - delta_33, tau10.0_precise_dC1dC1 = tau10.0_precise_coeff_5sp[[1]][3,3] - delta_33)
for(j in 2:200) precise_data <- rbind.data.frame(precise_data, c(rk4_result$t[j], precise_coeff_5sp[[j]][3,3] - delta_33, inst_precise_coeff_5sp[[j]][3,3] - delta_33, tau0.5_precise_coeff_5sp[[j]][3,3] - delta_33, tau1.0_precise_coeff_5sp[[j]][3,3] - delta_33, tau2.0_precise_coeff_5sp[[j]][3,3] - delta_33, tau10.0_precise_coeff_5sp[[j]][3,3] - delta_33))

plot(rk4_result$t[101:181], tau2*dC1dC1(rk4_result)[101:181], type = "l", col = "black", ylim = c(-0.005, 0.005), xlab = "time", ylab = "Interaction strengths C1 -> C1", lwd = 1, main = expression(paste(tau, "= 0.01", sep="")))
par(new = T)
plot(rk4_result$t[101:181], precise_data$inst_precise_dC1dC1[101:181], type = "l", col = "#ff4b00", lwd = 2, lty = 2, ylim = c(-0.005, 0.005), xlab = "", ylab = "")

legend("bottomright", 
          legend = c("instantaneous interaction strength", "cumulative interaction strength"),  
          col = c("black", "#ff4b00"), 
          lty = c(1, 2),              
          cex = c(0.8)
)


plot(rk4_result$t[101:181], tau3*dC1dC1(rk4_result)[101:181], type = "l", col = "black", ylim = c(-0.4, 0.3), xlab = "time", ylab = "Interaction strengths C1 -> C1", lwd = 1, main = expression(paste(tau, "= 0.5", sep="")))
par(new = T)
plot(rk4_result$t[101:181], precise_data$tau0.5_precise_dC1dC1[101:181], type = "l", col = "#ff4b00", lwd = 2, lty = 2, ylim = c(-0.4, 0.3), xlab = "", ylab = "")




plot(rk4_result$t[101:181], tau4*dC1dC1(rk4_result)[101:181], type = "l", col = "black", ylim = c(0.0, 0.15), xlab = "time", ylab = "Interaction strengths C1 -> C1", lwd = 1, main = expression(paste(tau, "= 1.0", sep="")))
par(new = T)
plot(rk4_result$t[101:181], precise_data$tau1.0_precise_dC1dC1[101:181], type = "l", col = "#ff4b00", lwd = 2, lty = 2, ylim = c(0.0, 0.15), xlab = "", ylab = "")



plot(rk4_result$t[101:181], tau5*dC1dC1(rk4_result)[101:181], type = "l", col = "black", ylim = c(-0.4, 0.3), xlab = "time", ylab = "Interaction strengths C1 -> C1", lwd = 1, main = expression(paste(tau, "= 2.0", sep="")))
par(new = T)
plot(rk4_result$t[101:181], precise_data$tau2.0_precise_dC1dC1[101:181], type = "l", col = "#ff4b00", lwd = 2, lty = 2, ylim = c(-0.4, 0.3), xlab = "", ylab = "")



plot(rk4_result$t[101:181], tau1*dC1dC1(rk4_result)[101:181], type = "l", col = "black", ylim = c(-2, 2), xlab = "time", ylab = "Interaction strengths C1 -> C1", lwd = 1, main = expression(paste(tau, "= 5.0", sep="")))
par(new = T)
plot(rk4_result$t[101:181], precise_data$precise_dC1dC1[101:181], type = "l", col = "#ff4b00", lwd = 2, lty = 2, ylim = c(-2, 2), xlab = "", ylab = "")



plot(rk4_result$t[101:181], tau6*dC1dC1(rk4_result)[101:181], type = "l", col = "black", ylim = c(-2, 3), xlab = "time", ylab = "Interaction strengths C1 -> C1", lwd = 1, main = expression(paste(tau, "= 10.0", sep="")))
par(new = T)
plot(rk4_result$t[101:181], precise_data$tau10.0_precise_dC1dC1[101:181], type = "l", col = "#ff4b00", lwd = 2, lty = 2, ylim = c(-2, 3), xlab = "", ylab = "")

[10.2.2] For each graph as pdf for figure 4
pdf("fig4a.pdf", width = 4, height = 4)
plot(rk4_result$t[101:181], tau2*dC1dC1(rk4_result)[101:181], type = "l", col = "black", ylim = c(-0.005, 0.005), xlab = "time", ylab = "Interaction strengths C1 -> C1", lwd = 1, main = expression(paste(tau, "= 0.01", sep="")))
par(new = T)
plot(rk4_result$t[101:181], precise_data$inst_precise_dC1dC1[101:181], type = "l", col = "#ff4b00", lwd = 2, lty = 2, ylim = c(-0.005, 0.005), xlab = "", ylab = "")

legend("bottomright", 
          legend = c("instantaneous interaction strength", "cumulative interaction strength"),  
          col = c("black", "#ff4b00"), 
          lty = c(1, 2),              
          cex = c(0.8)
)
dev.off()
null device 
          1 
pdf("fig4b.pdf", width = 4, height = 4)
plot(rk4_result$t[101:181], tau3*dC1dC1(rk4_result)[101:181], type = "l", col = "black", ylim = c(-0.4, 0.3), xlab = "time", ylab = "Interaction strengths C1 -> C1", lwd = 1, main = expression(paste(tau, "= 0.5", sep="")))
par(new = T)
plot(rk4_result$t[101:181], precise_data$tau0.5_precise_dC1dC1[101:181], type = "l", col = "#ff4b00", lwd = 2, lty = 2, ylim = c(-0.4, 0.3), xlab = "", ylab = "")
dev.off()
null device 
          1 
pdf("fig4c.pdf", width = 4, height = 4)
plot(rk4_result$t[101:181], tau4*dC1dC1(rk4_result)[101:181], type = "l", col = "black", ylim = c(0.0, 0.15), xlab = "time", ylab = "Interaction strengths C1 -> C1", lwd = 1, main = expression(paste(tau, "= 1.0", sep="")))
par(new = T)
plot(rk4_result$t[101:181], precise_data$tau1.0_precise_dC1dC1[101:181], type = "l", col = "#ff4b00", lwd = 2, lty = 2, ylim = c(0.0, 0.15), xlab = "", ylab = "")
dev.off()
null device 
          1 
pdf("fig4d.pdf", width = 4, height = 4)
plot(rk4_result$t[101:181], tau5*dC1dC1(rk4_result)[101:181], type = "l", col = "black", ylim = c(-0.4, 0.3), xlab = "time", ylab = "Interaction strengths C1 -> C1", lwd = 1, main = expression(paste(tau, "= 2.0", sep="")))
par(new = T)
plot(rk4_result$t[101:181], precise_data$tau2.0_precise_dC1dC1[101:181], type = "l", col = "#ff4b00", lwd = 2, lty = 2, ylim = c(-0.4, 0.3), xlab = "", ylab = "")
dev.off()
null device 
          1 
pdf("fig4e.pdf", width = 4, height = 4)
plot(rk4_result$t[101:181], tau1*dC1dC1(rk4_result)[101:181], type = "l", col = "black", ylim = c(-2, 2), xlab = "time", ylab = "Interaction strengths C1 -> C1", lwd = 1, main = expression(paste(tau, "= 5.0", sep="")))
par(new = T)
plot(rk4_result$t[101:181], precise_data$precise_dC1dC1[101:181], type = "l", col = "#ff4b00", lwd = 2, lty = 2, ylim = c(-2, 2), xlab = "", ylab = "")
dev.off()
null device 
          1 
pdf("fig4f.pdf", width = 4, height = 4)
plot(rk4_result$t[101:181], tau6*dC1dC1(rk4_result)[101:181], type = "l", col = "black", ylim = c(-2, 3), xlab = "time", ylab = "Interaction strengths C1 -> C1", lwd = 1, main = expression(paste(tau, "= 10.0", sep="")))
par(new = T)
plot(rk4_result$t[101:181], precise_data$tau10.0_precise_dC1dC1[101:181], type = "l", col = "#ff4b00", lwd = 2, lty = 2, ylim = c(-2, 3), xlab = "", ylab = "")
dev.off()
null device 
          1 
LS0tCnRpdGxlOiAiUiBOb3RlYm9vayBmb3IgTURSIFMtbWFwIGZvciBERSBhbmQgT0RFIG1vZGVscyB2ZXJzaW9uIDQiCm91dHB1dDogaHRtbF9ub3RlYm9vawotLS0KIyMjIFswXSBQYWNrYWdlcyBsb2FkaW5nCnJFRE0gc2hvdWxkIGJlIHRoZSB2ZXJzaW9uIDEuMi4zCgpodHRwczovL2NyYW4uci1wcm9qZWN0Lm9yZy9zcmMvY29udHJpYi9BcmNoaXZlL3JFRE0vCgpgYGB7cn0KbGlicmFyeShtYXRoamF4cikKbGlicmFyeShyRURNKTsgcGFja2FnZVZlcnNpb24oInJFRE0iKQpsaWJyYXJ5KHBhcmFsbGVsKQpsaWJyYXJ5KGRvUGFyYWxsZWwpCmxpYnJhcnkoZm9yZWFjaCkKbGlicmFyeShLZW5kYWxsKQpsaWJyYXJ5KE1BU1MpCmxpYnJhcnkoZHBseXIpCmxpYnJhcnkoZ2xtbmV0KQpsaWJyYXJ5KGdncGxvdDIpCiNzb3VyY2UoIi4uL0RlbW9fTURSX2Z1bmN0aW9uLlIiKQpzb3VyY2UoIi4vRGVtb19NRFJfZnVuY3Rpb24yLlIiKSAjZnJvbSAyMDI0LzA1LzA3CmBgYAoKIyMjIFsxXSBHZW5lcmFsIGZ1bmN0aW9ucyBmb3IgT0RFcwo0dGgtb3JkZXIgZXhwbGljaXQgUnVuZ2UtS3V0dGEgbWV0aG9kIHdpdGggYSBmaXhlZCBpbnRlcnZhbCBmdW5jdGlvbgpgYGB7cn0Kcms0IDwtIGZ1bmN0aW9uKGluX3ZlYywgcmVmX2RhdGEgPSBOVUxMLCB0aW1lLCBoX2ludGVydmFsLCBkaW0sIGRpZmZfdmVjKQp7CiAgI2luX3ZlYzogdGhlIHZlY3RvciB3aXRoIHRoZSB2YWx1ZSBhdCAidGltZSIKICAjb3V0X3ZlYzogdGhlIHZlY3RvciB3aXRoIHdoaWNoIHRoZSB1cGRhdGVkIHZlY3RvciB2YWx1ZSBhZnRlciBvbmUgdGltZSBzdGVwIGlzIHNhdmVkCiAgI3RpbWU6IHRpbWUgdmFsdWUKICAjaF9pbnRlcnZhbDogdGltZSBzdGVwIGZvciBkaXNjcml0aXppbmcgT0RFCiAgI2RpbTogZGltZW5zaW9uIG9mIHRoZSBPREUKICAjZGlmZl92ZWM6IGZ1bmN0aW9uIHRoYXQgZGV0ZXJtaW5lcyB0aGUgci5oLnMuIG9mIHRoZSBPREUKICAKICBrMSA8LSBudW1lcmljKGRpbSkKICBrMiA8LSBudW1lcmljKGRpbSkKICBrMyA8LSBudW1lcmljKGRpbSkKICBrNCA8LSBudW1lcmljKGRpbSkKICB0ZW1wX3ZlYyA8LSBudW1lcmljKGRpbSkKICBoX2hhbGYgPC0gaF9pbnRlcnZhbCAvIDIuMAogIHRfaCA8LSB0aW1lICsgaF9oYWxmCiAgCiAgazEgPC0gZGlmZl92ZWMoaW5fdmVjLCByZWZfZGF0YSwgdGltZSwgaF9pbnRlcnZhbCwgZGltKSAgIyBjYWxjdWxhdGUgazEKICB0ZW1wX3ZlYyA8LSBpbl92ZWMgKyBoX2hhbGYgKiBrMQogIGsyIDwtIGRpZmZfdmVjKHRlbXBfdmVjLCByZWZfZGF0YSwgdF9oLCBoX2ludGVydmFsLCBkaW0pICAjIGNhbGN1bGF0ZSBrMgogIHRlbXBfdmVjIDwtIGluX3ZlYyArIGhfaGFsZiAqIGsyCiAgazMgPC0gZGlmZl92ZWModGVtcF92ZWMsIHJlZl9kYXRhLCB0X2gsIGhfaW50ZXJ2YWwsIGRpbSkgICMgY2FsY3VsYXRlIGszCiAgdGVtcF92ZWMgPC0gaW5fdmVjICsgaF9pbnRlcnZhbCAqIGszCiAgazQgPC0gZGlmZl92ZWModGVtcF92ZWMsIHJlZl9kYXRhLCB0aW1lICsgaF9pbnRlcnZhbCwgaF9pbnRlcnZhbCwgZGltKSAgIyBjYWxjdWxhdGUgazQKICAKICB0ZW1wX3ZlYyA8LSBpbl92ZWMgKyAoaF9pbnRlcnZhbCAvIDYuMCkgKiAoazEgKyAyLjAgKiBrMiArIDIuMCAqIGszICsgazQpCiAgdGVtcF92ZWMKfQoKYGBgCgoKIyMjIFsyXSBNb2RlbDAxIHNldHRpbmcKSW50ZXJhY3Rpb24gc3RyZW5ndGggZXN0aW1hdGlvbiBmb3IgdGltZS1kaXNjcmV0ZSBtb2RlbCAoREUpIGZyYW1ld29yawoKIyMjIyBbMi4xXSBNb2RlbCBlcXVhdGlvbnMKMi1Ib3N0IDItUGFyYXNpdG9pZCBTeXN0ZW0gd2l0aCBuYXR1cmFsIG1vcnRhbGl0eSAoaS5lLiwgd2l0aCBvdmVybGFwcGluZyBnZW5lcmF0aW9ucykKCk5vdGU6IFdoZW4gdGhlIG5hdHVyYWwgbW9ydGFsaXR5IGdvZXMgdG8gaW5maW5pdHksIHRoZSBtb2RlbCBjb252ZXJnZXMgdG8gMi1Ib3N0IDItUGFyYXNpdG9pZCBOaWNvbHNvbi1CYWlseSBNb2RlbAoKXFsKSF97ayx0KzF9ID0gSF97ayx0fSArIHJfayBleHBbLWFfe2t9SF97ayx0fSAtIGNfezFrfSBQX3sxLHR9IC0gY197Mmt9IFBfezIsIHR9XSBIX3trLHR9IC0gKDEgLSBleHBbLWFfe2t9SF97ayx0fSAtIGNfezFrfSBQX3sxLHR9IC0gY197Mmt9IFBfezIsdH0gIC0gbV97SCxrfV0pIEhfe2ssdH0gIFxxdWFkIChrPTEsMikgXHRhZ3tEMX0KXF0KSXQgaXMgc2V0IGFzIApcWwpIX3trLHQrMX0gPSBIX3trLHR9ICsgRl97SGt9KEhfezEsdH0sIEhfezIsdH0sIFBfezEsdH0sIFBfezIsdH0pClxdCgpcWwpQX3tqLHQrMX0gPSBQX3tqLHR9ICsgXHN1bV97az0xLDJ9IGV4cCgtYV9rIEhfe2ssdH0pICgxIC0gIGV4cFstY197MWt9IFBfezEsdH0gLSBjX3sya30gUF97Mix0fV0pIFxmcmFje2Nfe2prfSBQX3tqLHR9fXtjX3sxa30gUF97MSx0fSArIGNfezJrfSBQX3syLHR9fSBIX3trLHR9IC0oMSAtIGV4cCgtbV97UCxqfSkpIFBfe2osdH0gXHF1YWQgKGo9MSwyKSBcdGFne0QyfQpcXQpJdCBpcyBzZXQgYXMgClxbClBfe2osdCsxfSA9IFBfe2osdH0gKyBGX3tQan0oSF97MSx0fSwgSF97Mix0fSwgUF97MSx0fSwgUF97Mix0fSkKXF0KCgojIyMjIFsyLjJdIFBhcmFtZXRlcnMgYW5kIHNldHRpbmdzIGZvciB0aGUgNC1zcGVjaWVzIGNvdXBsZWQgaG9zdC1wYXJhc2l0b2lkIG1vZGVsCiMjIyMjIFsyLjIuMV0gUGFyYW1ldGVyIHZhbHVlIHNldHRpbmcKYGBge3J9CnIxIDwtIDIuMApyMiA8LSAyLjAKYTEgPC0gMC4xCmEyIDwtIDAuMQpjMTEgPC0gMC4zICNQMSAtPiBIMQpjMjEgPC0gMC4xICNQMiAtPiBIMQpjMTIgPC0gMC4xICNQMSAtPiBIMgpjMjIgPC0gMC4zICNQMiAtPiBIMgptSDEgPC0gMC4xCm1IMiA8LSAwLjEKbVAxIDwtIDAuMQptUDIgPC0gMC4xCmBgYAojIyMjIyBbMi4yLjJdIFNldHRpbmcgZm9yIG51bWVyaWNhbCBjYWxjdWxhdGlvbnMKYGBge3J9CmpfSG9zdDEgPC0gMQpqX0hvc3QyIDwtIDIKal9QYXJhczEgPC0gMwpqX1BhcmFzMiA8LSA0CmBgYAojIyMjIyBbMi4yLjNdIEZ1bmN0aW9ucyBzcGVjaWZpYyB0byA0LXNwIG1vZGVsCk5vdGUgdGhhdCBGSDEsIEZIMiwgRlAxLCBGUDIsIGFyZSBkZWZpbmVkIGFzIHRoZSBjaGFuZ2VzIG9mIHRoZSBhYnVuZGFuY2UgKFhfdCsxIC0gWF90KQpgYGB7cn0KRkgxIDwtIGZ1bmN0aW9uKGluX3ZlYywgdCkgewogIHRlcm0xIDwtIHIxKmV4cCgtYTEgKiBpbl92ZWNbal9Ib3N0MV0gLSBjMTEgKiBpbl92ZWNbal9QYXJhczFdIC0gYzIxICogaW5fdmVjW2pfUGFyYXMyXSkgKiBpbl92ZWNbal9Ib3N0MV0KICB0ZXJtMiA8LSAoMS4wIC0gZXhwKC1hMSAqIGluX3ZlY1tqX0hvc3QxXSAtIGMxMSAqIGluX3ZlY1tqX1BhcmFzMV0gLSBjMjEgKiBpbl92ZWNbal9QYXJhczJdIC0gbUgxKSkgKiBpbl92ZWNbal9Ib3N0MV0KICByZXR1cm4odGVybTEgLSB0ZXJtMikKfQoKRkgyIDwtIGZ1bmN0aW9uKGluX3ZlYywgdCkgewogIHRlcm0xIDwtIHIyKmV4cCgtYTIgKiBpbl92ZWNbal9Ib3N0Ml0gLSBjMTIgKiBpbl92ZWNbal9QYXJhczFdIC0gYzIyICogaW5fdmVjW2pfUGFyYXMyXSkgKiBpbl92ZWNbal9Ib3N0Ml0KICB0ZXJtMiA8LSAoMS4wIC0gZXhwKC1hMiAqIGluX3ZlY1tqX0hvc3QyXSAtIGMxMiAqIGluX3ZlY1tqX1BhcmFzMV0gLSBjMjIgKiBpbl92ZWNbal9QYXJhczJdIC0gbUgyKSkgKiBpbl92ZWNbal9Ib3N0Ml0KICByZXR1cm4odGVybTEgLSB0ZXJtMikKfQogIApGUDEgPC0gZnVuY3Rpb24oaW5fdmVjLCB0KSB7CiAgdGVybTEgPC0gZXhwKC1hMSAqIGluX3ZlY1tqX0hvc3QxXSkgKiAoMSAtIGV4cCgtYzExICogaW5fdmVjW2pfUGFyYXMxXSAtIGMyMSAqIGluX3ZlY1tqX1BhcmFzMl0pKSAqIGMxMSAqIGluX3ZlY1tqX1BhcmFzMV0gLyAoYzExICogaW5fdmVjW2pfUGFyYXMxXSArIGMyMSAqIGluX3ZlY1tqX1BhcmFzMl0pICogaW5fdmVjW2pfSG9zdDFdCiAgCiAgdGVybTIgPC0gZXhwKC1hMiAqIGluX3ZlY1tqX0hvc3QyXSkgKiAoMSAtIGV4cCgtYzEyICogaW5fdmVjW2pfUGFyYXMxXSAtIGMyMiAqIGluX3ZlY1tqX1BhcmFzMl0pKSAqIGMxMiAqIGluX3ZlY1tqX1BhcmFzMV0gLyAoYzEyICogaW5fdmVjW2pfUGFyYXMxXSArIGMyMiAqIGluX3ZlY1tqX1BhcmFzMl0pICogaW5fdmVjW2pfSG9zdDJdCiAgCiAgdGVybTMgPC0gKDEuMCAtIGV4cCgtIG1QMSkpICogaW5fdmVjW2pfUGFyYXMxXQogIHJldHVybih0ZXJtMSArIHRlcm0yIC0gdGVybTMpCn0KICAKRlAyIDwtIGZ1bmN0aW9uKGluX3ZlYywgdCkgewogIHRlcm0xIDwtIGV4cCgtYTEgKiBpbl92ZWNbal9Ib3N0MV0pICogKDEgLSBleHAoLWMxMSAqIGluX3ZlY1tqX1BhcmFzMV0gLSBjMjEgKiBpbl92ZWNbal9QYXJhczJdKSkgKiBjMjEgKiBpbl92ZWNbal9QYXJhczJdIC8gKGMxMSAqIGluX3ZlY1tqX1BhcmFzMV0gKyBjMjEgKiBpbl92ZWNbal9QYXJhczJdKSAqIGluX3ZlY1tqX0hvc3QxXQogIAogIHRlcm0yIDwtIGV4cCgtYTIgKiBpbl92ZWNbal9Ib3N0Ml0pICogKDEgLSBleHAoLWMxMiAqIGluX3ZlY1tqX1BhcmFzMV0gLSBjMjIgKiBpbl92ZWNbal9QYXJhczJdKSkgKiBjMjIgKiBpbl92ZWNbal9QYXJhczJdIC8gKGMxMiAqIGluX3ZlY1tqX1BhcmFzMV0gKyBjMjIgKiBpbl92ZWNbal9QYXJhczJdKSAqIGluX3ZlY1tqX0hvc3QyXQogIAogIHRlcm0zIDwtICgxLjAgLSBleHAoLSBtUDIpKSAqIGluX3ZlY1tqX1BhcmFzMl0KICByZXR1cm4odGVybTEgKyB0ZXJtMiAtIHRlcm0zKQp9CgojZnVuY3Rpb24gdG8gY2FsY3VsYXRlIGFsbCBjaGFuZ2VzIGZvdXIgZGltZW5zaW9uYWwKZGlmZl80SFAgPC0gZnVuY3Rpb24oaW5fdmVjLCB0LCBkaW0pewogIHRlbXBfdmVjIDwtIG51bWVyaWMoZGltKQogIHRlbXBfdmVjW2pfSG9zdDFdIDwtIEZIMShpbl92ZWMsIHQpCiAgdGVtcF92ZWNbal9Ib3N0Ml0gPC0gRkgyKGluX3ZlYywgdCkKICB0ZW1wX3ZlY1tqX1BhcmFzMV0gPC0gRlAxKGluX3ZlYywgdCkKICB0ZW1wX3ZlY1tqX1BhcmFzMl0gPC0gRlAyKGluX3ZlYywgdCkKICB0ZW1wX3ZlYwp9IApgYGAKCiMjIyMjIFsyLjIuNF0gSW5pdGlhbCBzZXR0aW5nIGFuZCBjb25kaXRpb25zCmBgYHtyfQpkaW1fbW9kZWwyIDwtIDQKbnZfNEhQMCA8LSBudW1lcmljKGRpbV9tb2RlbDIpCm52XzRIUCA8LSBudW1lcmljKGRpbV9tb2RlbDIpCgpudl80SFAwW2pfSG9zdDFdIDwtIDEuMApudl80SFAwW2pfSG9zdDJdIDwtIDEuMApudl80SFAwW2pfUGFyYXMxXSA8LSAwLjEKbnZfNEhQMFtqX1BhcmFzMl0gPC0gMC4xCgpgYGAKIyMjIyBbMi4zXSBTb2x2aW5nIHRoZSBtb2RlbAojIyMjIyBbMi4zLjFdIFRyaWFsIHdpdGggYSBzaW5nbGUgSG9zdCAtIHNpbmdsZSBQYXJhc2l0b2lkIHN5c3RlbQpgYGB7cn0KdCA8LSAwICAjIGluaXRpYWwgY29uZGl0aW9uIChpbml0aWFsIHRpbWUsIDApCmVuZF90aW1lIDwtIDEwMDAKCiNTZXR0aW5nIGluaXRpYWwgY29uZGl0aW9uCm52XzRIUFtqX0hvc3QxXSA8LSAxLjAKbnZfNEhQW2pfSG9zdDJdIDwtIDAuMApudl80SFBbal9QYXJhczFdIDwtIDAuMQpudl80SFBbal9QYXJhczJdIDwtIDAuMAoKCiMgd3JpdGUgaW5pdGlhbCBjb25kaXRpb24KY2F0KHQsIG52XzRIUCwgIlxuIikKCgojIHJlY29yZCB0aGUgaW5pdGlhbCBjb25kaXRpb24KSFBfcmVzdWx0IDwtIGRhdGEuZnJhbWUodCA9IHQsIEgxID0gbnZfNEhQW2pfSG9zdDFdLCBIMiA9IG52XzRIUFtqX0hvc3QyXSwgUDEgPSBudl80SFBbal9QYXJhczFdLCBQMiA9IG52XzRIUFtqX1BhcmFzMl0pCiNGb3IgdGhlIHRyYW5zaWVudCBkeW5hbWljcyAoUlVOIEJVUk4pCmZvcihpIGluIDE6ZW5kX3RpbWUpewogIG52XzRIUCA8LSBudl80SFAgKyBkaWZmXzRIUChudl80SFAsIHQsIGRpbV9tb2RlbDIpCiAgdCA8LSB0ICsgMSAjdXBkYXRlIHRpbWUKICBIUF9yZXN1bHQgPC0gcmJpbmQuZGF0YS5mcmFtZShIUF9yZXN1bHQsIGModCwgbnZfNEhQW2pfSG9zdDFdLCBudl80SFBbal9Ib3N0Ml0sIG52XzRIUFtqX1BhcmFzMV0sIG52XzRIUFtqX1BhcmFzMl0pKQp9CgpoZWFkKEhQX3Jlc3VsdCkKCiNUcmlhbCBvZiB0aGUgcGxvdApwbG90KEhQX3Jlc3VsdCR0LCBIUF9yZXN1bHQkSDEsIHR5cGUgPSAibCIsIHlsaW0gPSBjKDAsMjApKQpwYXIobmV3ID0gVCkKcGxvdChIUF9yZXN1bHQkdCwgSFBfcmVzdWx0JFAxLCB0eXBlID0gImwiLCB5bGltID0gYygwLDIwKSwgY29sID0gInJlZCIpCmBgYAojIyMjIyBbMi4zLjJdIFRyaWFsIHdpdGggdHdvIHBhaXJzIG9mIEhvc3QgLSBQYXJhc2l0b2lkIHN5c3RlbQpgYGB7cn0KdCA8LSAwICAjIGluaXRpYWwgY29uZGl0aW9uIChpbml0aWFsIHRpbWUsIDApCmVuZF90aW1lIDwtIDIwMDAKCiNTZXR0aW5nIGluaXRpYWwgY29uZGl0aW9uOyBpdCBpcyBpbXBvcnRhbnQgdG8gc3RhcnQgd2l0aCBhc3ltbWV0cmljIGRlbnNpdGllcyB0byByZWFjaCBxdWlja2x5IHRoZSBjaGFvdGljIGF0dHJhY3Rvcgpudl80SFBbal9Ib3N0MV0gPC0gMS4wCm52XzRIUFtqX0hvc3QyXSA8LSAwLjUKbnZfNEhQW2pfUGFyYXMxXSA8LSAwLjEKbnZfNEhQW2pfUGFyYXMyXSA8LSAwLjIKCgojIHdyaXRlIGluaXRpYWwgY29uZGl0aW9uCmNhdCh0LCBudl80SFAsICJcbiIpCgoKIyByZWNvcmQgdGhlIGluaXRpYWwgY29uZGl0aW9uCkhQX3Jlc3VsdCA8LSBkYXRhLmZyYW1lKHQgPSB0LCBIMSA9IG52XzRIUFtqX0hvc3QxXSwgSDIgPSBudl80SFBbal9Ib3N0Ml0sIFAxID0gbnZfNEhQW2pfUGFyYXMxXSwgUDIgPSBudl80SFBbal9QYXJhczJdKQojRm9yIHRoZSB0cmFuc2llbnQgZHluYW1pY3MgKFJVTiBCVVJOKQpmb3IoaSBpbiAxOmVuZF90aW1lKXsKICBudl80SFAgPC0gbnZfNEhQICsgZGlmZl80SFAobnZfNEhQLCB0LCBkaW1fbW9kZWwyKQogIHQgPC0gdCArIDEgI3VwZGF0ZSB0aW1lCiAgSFBfcmVzdWx0IDwtIHJiaW5kLmRhdGEuZnJhbWUoSFBfcmVzdWx0LCBjKHQsIG52XzRIUFtqX0hvc3QxXSwgbnZfNEhQW2pfSG9zdDJdLCBudl80SFBbal9QYXJhczFdLCBudl80SFBbal9QYXJhczJdKSkKfQoKaGVhZChIUF9yZXN1bHQpCgojVHJpYWwgb2YgdGhlIHBsb3QKcGxvdChIUF9yZXN1bHQkdCwgSFBfcmVzdWx0JEgxLCB0eXBlID0gImwiLCB5bGltID0gYygwLDUpKQpwYXIobmV3ID0gVCkKcGxvdChIUF9yZXN1bHQkdCwgSFBfcmVzdWx0JFAxLCB0eXBlID0gImwiLCB5bGltID0gYygwLDUpLCBjb2wgPSAicmVkIikKcGFyKG5ldyA9IFQpCnBsb3QoSFBfcmVzdWx0JHQsIEhQX3Jlc3VsdCRIMiwgdHlwZSA9ICJsIiwgeWxpbSA9IGMoMCw1KSwgbHR5ID0gImRhc2hlZCIpCnBhcihuZXcgPSBUKQpwbG90KEhQX3Jlc3VsdCR0LCBIUF9yZXN1bHQkUDIsIHR5cGUgPSAibCIsIHlsaW0gPSBjKDAsNSksIGNvbCA9ICJyZWQiLCBsdHkgPSAiZGFzaGVkIikKCkRBWSA9IFN5cy5EYXRlKCkKc2F2ZVJEUyhIUF9yZXN1bHQsIHBhc3RlKCJIUDRwX3Jlc3VsdF8iLCBEQVksICIub2JqIiwgc2VwID0gIiIpKQpgYGAKIyMjIFszXSBBIHNpbXBsZSBhbmFseXNpcyB3aXRoIG11bHRpdmFyaWF0ZSBTLW1hcApCYXNlZCBvbiBodHRwczovL3VzaGlvLWVjb2xvZ3ktYmxvZy5ibG9nc3BvdC5jb20vMjAxOS8xMi8yMDE5MTIyNWJsb2dnZXIwMDA3Lmh0bWwKCiMjIyMgWzMuMV0gQW5hbHlzaXMgd2l0aCBzdGFuZGFyZGl6YXRpb24KTG9hZGluZyB0aGUgZGVmYXVsdCBkYXRhIGF0IDIwMjQtMDctMjUgYW5kIHRha2luZyB0aGUgZmluYWwgMjAwIGRhdGEgcG9pbnRzIGluIHRoZSB0aW1lIHNlcmllcwpgYGB7cn0KSFBfcmVzdWx0IDwtIHJlYWRSRFMoIkhQNHBfcmVzdWx0XzIwMjQtMDctMjUub2JqIikKSFBfcmVzdWx0IDwtIEhQX3Jlc3VsdFsxODAxOjIwMDAsIF0KYGBgCgojIyMjIyBbMy4xLjFdIFN0YW5kYXJkaXphdGlvbgpgYGB7cn0KSFBfcmVzdWx0Lm1lYW4gPC0gYXBwbHkoSFBfcmVzdWx0WywgLTFdLCAyLCBtZWFuLCBuYS5ybSA9IFQpICAjIG1lYW4gYWJ1bmRhbmNlCkhQX3Jlc3VsdC5zZCA8LSBhcHBseShIUF9yZXN1bHRbLCAtMV0sIDIsIHNkLCBuYS5ybSA9IFQpICAgICAgIyBTRCBvZiBhYnVuZGFuY2UgCgptZWFuX21hdCA8LSBtYXRyaXgoSFBfcmVzdWx0Lm1lYW4sIG5yb3cgPSBucm93KEhQX3Jlc3VsdCkgLCBuY29sID0gbGVuZ3RoKEhQX3Jlc3VsdC5tZWFuKSwgYnlyb3cgPSBUUlVFKQpzZF9tYXQgPC0gbWF0cml4KEhQX3Jlc3VsdC5zZCwgbnJvdyA9IG5yb3coSFBfcmVzdWx0KSAsIG5jb2wgPSBsZW5ndGgoSFBfcmVzdWx0Lm1lYW4pLCBieXJvdyA9IFRSVUUpCgpIUF9yZXN1bHRfcyA8LSAoSFBfcmVzdWx0WywgLTFdIC0gbWVhbl9tYXQpIC9zZF9tYXQgIyBTdGFuZGFyZGl6ZWQgZGF0YSBzZXQKaGVhZChIUF9yZXN1bHRfcykKYGBgCiMjIyMjIFszLjEuMl0gQW5hbHlzaXMgd2l0aCB0aGUgc3RhbmRhcmRpemVkIHRpbWUgc2VyaWVzIGRhdGEgCmBgYHtyfQojIGRhdGEgYmxvY2sgZm9yIHNtYXAKSFBfc21hcF9ibG9ja19zIDwtIGRhdGEuZnJhbWUoSDEgPSBIUF9yZXN1bHRfcyRIMSwgSDIgPSBIUF9yZXN1bHRfcyRIMiwgUDEgPSBIUF9yZXN1bHRfcyRQMSwgUDIgPSBIUF9yZXN1bHRfcyRQMikKCiMgZGVsZXRlIGEgZmV3IGNvbHVtbgojIGNvbmR1Y3RpbmcgdW5pdmFyaWF0ZSBzbWFwIGZvciBvYnRhaW5pbmcgdGhlIG9wdGltYWwgdGhldGEKSFBfbV9zbWFwX3Jlc19zIDwtIGJsb2NrX2xubHAoSFBfc21hcF9ibG9ja19zLCBtZXRob2QgPSAicy1tYXAiLAogICAgICAgICAgICAgICAgICAgICAgICAgdGFyZ2V0X2NvbHVtbiA9IGpfSG9zdDEsIAogICAgICAgICAgICAgICAgICAgICAgICAgdGhldGEgPSBjKDAsIDFlLTA0LCAzZS0wNCwgMC4wMDEsIDAuMDAzLCAwLjAxLCAwLjAzLCAwLjEsIDAuMywgMC41LCAwLjc1LCAxLCAxLjUsIDIsIDMsIDQsIDYsIDgpLAogICAgICAgICAgICAgICAgICAgICAgICAgc2lsZW50ID0gVFJVRSkKYGBgClBsb3R0aW5nIHRoZSBlZmZlY3Qgb2YgdGhldGEKYGBge3J9CnBsb3QoSFBfbV9zbWFwX3Jlc19zJHRoZXRhLCBIUF9tX3NtYXBfcmVzX3Mkcm1zZSwgdHlwZSA9ICJiIikKKEhQX29wdF90aGV0YV9zIDwtIEhQX21fc21hcF9yZXNfcyR0aGV0YVt3aGljaC5taW4oSFBfbV9zbWFwX3Jlc19zJHJtc2UpXSkKYGBgCgpDb25kdWN0aW5nIG11bHRpdmFyaWF0ZSBzbWFwIHdpdGggdGhlIG9wdGltYWwgdGhldGEKYGBge3J9CkhQX21fc21hcF9yZXMyX3MgPC0gYmxvY2tfbG5scChIUF9zbWFwX2Jsb2NrX3MsIG1ldGhvZCA9ICJzLW1hcCIsIAogICAgICAgICAgICAgICAgICAgICAgICAgICAgICB0YXJnZXRfY29sdW1uID0gal9Ib3N0MSwgCiAgICAgICAgICAgICAgICAgICAgICAgICAgICAgIHRoZXRhID0gSFBfb3B0X3RoZXRhX3MsIAogICAgICAgICAgICAgICAgICAgICAgICAgICAgICBzaWxlbnQgPSBUUlVFLCAKICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgc2F2ZV9zbWFwX2NvZWZmaWNpZW50cyA9IFRSVUUpCmhlYWQoYXMuZGF0YS5mcmFtZShIUF9tX3NtYXBfcmVzMl9zJHNtYXBfY29lZmZpY2llbnRzW1sxXV0pKQpgYGAKIyMjIyMgWzMuMS4zXSBQbG90dGluZyB0aGUgcmVzdWx0cwpgYGB7cn0KZmluYWxfSUQgPC0gMjAwCmRlbHRhXzExIDwtIDEKcGxvdChIUF9yZXN1bHQkdFstZmluYWxfSURdLCBIUF9tX3NtYXBfcmVzMl9zJHNtYXBfY29lZmZpY2llbnRzW1sxXV0kY18xWy1maW5hbF9JRF0gLSBkZWx0YV8xMSwgdHlwZSA9ICJsIiwgY29sID0gMSwgeWxpbSA9IGMoLTAuOSwgMS4wKSwgeGxhYiA9ICJ0aW1lIiwgeWxhYiA9ICJTbWFwIGNvZWZmaWNpZW50OiBYIC0+IEhvc3QxIiwgbWFpbiA9ICJTLW1hcCBmb3IgSDEiKQpwYXIobmV3ID0gVCkKcGxvdChIUF9yZXN1bHQkdFstZmluYWxfSURdLCBIUF9tX3NtYXBfcmVzMl9zJHNtYXBfY29lZmZpY2llbnRzW1sxXV0kY18yWy1maW5hbF9JRF0sIHR5cGUgPSAibCIsIGNvbCA9ICJyZWQiLCB5bGltID0gYygtMC45LCAxLjApLCB4bGFiID0gIiIsIHlsYWIgPSAiIikKcGFyKG5ldyA9IFQpCnBsb3QoSFBfcmVzdWx0JHRbLWZpbmFsX0lEXSwgSFBfbV9zbWFwX3JlczJfcyRzbWFwX2NvZWZmaWNpZW50c1tbMV1dJGNfM1stZmluYWxfSURdLCB0eXBlID0gImwiLCBjb2wgPSAiYmx1ZSIsIHlsaW0gPSBjKC0wLjksIDEuMCksIHhsYWIgPSAiIiwgeWxhYiA9ICIiKQpwYXIobmV3ID0gVCkKcGxvdChIUF9yZXN1bHQkdFstZmluYWxfSURdLCBIUF9tX3NtYXBfcmVzMl9zJHNtYXBfY29lZmZpY2llbnRzW1sxXV0kY180Wy1maW5hbF9JRF0sIHR5cGUgPSAibCIsIGNvbCA9ICJncmVlbiIsIHlsaW0gPSBjKC0wLjksIDEuMCksIHhsYWIgPSAiIiwgeWxhYiA9ICIiKQoKbGVnZW5kKCJ0b3ByaWdodCIsIAogICAgICAgICAgbGVnZW5kID0gYygiUy1tYXAgZnJvbSBIMSB0byBIMSAtIGRlbHRhMTEiLCAiUy1tYXAgZnJvbSBIMiB0byBIMSIsICJTLW1hcCBmcm9tIFAxIHRvIEgxIiwgIlMtbWFwIGZyb20gUDIgdG8gSDEiKSwgIAogICAgICAgICAgY29sID0gYygiYmxhY2siLCAicmVkIiwgImJsdWUiLCAiZ3JlZW4iKSwgCiAgICAgICAgICBsdHkgPSBjKDEsIDEsIDEsIDEpLCAgICAgICAgICAgICAgCiAgICAgICAgICBjZXggPSAwLjgpICAgCmBgYAojIyMjIyBbMy4xLjRdIFBsb3R0aW5nIHRoZSByZXN1bHRzIGZvciBtYW51c2NyaXB0IChGaWcuMSkKCmBgYHtyfQpnZ19IUF9yZXN1bHQwMCA8LSBkYXRhLmZyYW1lKHRpbWUgPSBIUF9yZXN1bHQkdFstZmluYWxfSURdLCBzbWFwID0gSFBfbV9zbWFwX3JlczJfcyRzbWFwX2NvZWZmaWNpZW50c1tbMV1dJGNfMVstZmluYWxfSURdLCB0eXBlID0gcmVwKCJIMXRvSDEiLCAxOTkpKQpnZ19IUF9yZXN1bHQwMSA8LSBkYXRhLmZyYW1lKHRpbWUgPSBIUF9yZXN1bHQkdFstZmluYWxfSURdLCBzbWFwID0gSFBfbV9zbWFwX3JlczJfcyRzbWFwX2NvZWZmaWNpZW50c1tbMV1dJGNfMVstZmluYWxfSURdIC0gZGVsdGFfMTEsIHR5cGUgPSByZXAoIkgxdG9IMV9hZGp1c3RlZCIsIDE5OSkpCmdnX0hQX3Jlc3VsdDAyIDwtIGRhdGEuZnJhbWUodGltZSA9IEhQX3Jlc3VsdCR0Wy1maW5hbF9JRF0sIHNtYXAgPSBIUF9tX3NtYXBfcmVzMl9zJHNtYXBfY29lZmZpY2llbnRzW1sxXV0kY18yWy1maW5hbF9JRF0sIHR5cGUgPSByZXAoIkgydG9IMSIsIDE5OSkpCmdnX0hQX3Jlc3VsdDAzIDwtIGRhdGEuZnJhbWUodGltZSA9IEhQX3Jlc3VsdCR0Wy1maW5hbF9JRF0sIHNtYXAgPSBIUF9tX3NtYXBfcmVzMl9zJHNtYXBfY29lZmZpY2llbnRzW1sxXV0kY18zWy1maW5hbF9JRF0sIHR5cGUgPSByZXAoIlAxdG9IMSIsIDE5OSkpCmdnX0hQX3Jlc3VsdDA0IDwtIGRhdGEuZnJhbWUodGltZSA9IEhQX3Jlc3VsdCR0Wy1maW5hbF9JRF0sIHNtYXAgPSBIUF9tX3NtYXBfcmVzMl9zJHNtYXBfY29lZmZpY2llbnRzW1sxXV0kY180Wy1maW5hbF9JRF0sIHR5cGUgPSByZXAoIlAydG9IMSIsIDE5OSkpCgpnZ19IUF9yZXN1bHQgPC0gcmJpbmQuZGF0YS5mcmFtZShnZ19IUF9yZXN1bHQwMCwgZ2dfSFBfcmVzdWx0MDEpCmdnX0hQX3Jlc3VsdCA8LSByYmluZC5kYXRhLmZyYW1lKGdnX0hQX3Jlc3VsdCwgZ2dfSFBfcmVzdWx0MDIpCmdnX0hQX3Jlc3VsdCA8LSByYmluZC5kYXRhLmZyYW1lKGdnX0hQX3Jlc3VsdCwgZ2dfSFBfcmVzdWx0MDMpCmdnX0hQX3Jlc3VsdCA8LSByYmluZC5kYXRhLmZyYW1lKGdnX0hQX3Jlc3VsdCwgZ2dfSFBfcmVzdWx0MDQpCgoKZmlnMV9nZ3Bsb3QgPC0gZ2dwbG90KGRhdGEgPSBnZ19IUF9yZXN1bHQpICsKICBzY2FsZV9jb2xvdXJfbWFudWFsKHZhbHVlcyA9IGMoImJsYWNrIiwgIiNmZjRiMDAiLCIjNGRjNGZmIiwgIiNmNmFhMDAiLCAiIzgwNDAwMCIpKSArCiAgc2NhbGVfc2hhcGVfbWFudWFsKHZhbHVlcyA9IGMoMSwgMTUsIDE2LCAxNywgNSkpICsK44CAZ2VvbV9saW5lKGFlcyh4ID0gdGltZSwgeSA9IHNtYXAsIGdyb3VwID0gdHlwZSwgY29sb3IgPSB0eXBlKSkgKwogIGdlb21fcG9pbnQoYWVzKHggPSB0aW1lLCB5ID0gc21hcCwgY29sb3IgPSB0eXBlLCBzaGFwZSA9IHR5cGUpLCBzaXplID0gMikgKwogIHhsaW0oMTgwMCwgMTk5OSkgKyAgeWxpbSgtMC41LCAxLjUpICsgdGhlbWVfYncoKSArIHRoZW1lKGxlZ2VuZC5wb3NpdGlvbiA9ICJib3R0b20iKSArIAogIGxhYnModGl0bGUgPSAiRmlndXJlIDE6IFRpbWUgZXZvbHV0aW9uIG9mIFMtbWFwIGNvZWZmaWNpZW50cyIsIHggPSAidGltZSIsIHkgPSAiVW5hZGp1c3RlZCBhbmQgQWRqdXN0ZWQgUy1tYXAgY29lZmZpY2llbnRzIikgCnBsb3QoZmlnMV9nZ3Bsb3QpCmdnc2F2ZSgiZmlnMV9nZ3Bsb3QucGRmIiwgd2lkdGggPSAxMCwgaGVpZ2h0ID0gNSkKYGBgCgojIyMgWzRdIE1EUiBTLW1hcCBmb3IgMmhvc3QtMnBhcmFzaXRvaWQgc3lzdGVtCkFwcGx5aW5nIE1EUiBTLW1hcCB0byB0aGUgNHNwIGNvdXBsZWQgaG9zdC1wYXJhc2l0b2lkIG1vZGVsCgojIyMjIFs0LjFdIERhdGEgcHJlYXJyYW5nZW1lbnQKUmVhZCBkYXRhc2V0CmBgYHtyfQpkYS5yYW5nZSA8LSAxODAxOjIwMDAgIyBTdWJzYW1wbGUgZm9yIGRhdGEgYW5hbHlzaXMKb3V0LnNhbXBsZSA8LSBUICMgVC9GIGZvciBvdXQtb2Ytc2FtcGxlIGZvcmVjYXN0Cm5vdXQgPC0gMiAgIyBudW1iZXIgb2Ygb3V0LW9mLXNhbXBsZQoKZGEubmFtZSA8LSAnNHBfbW9kZWwnCmRvIDwtIHJlYWRSRFMoIkhQNHBfcmVzdWx0XzIwMjQtMDctMjUub2JqIikKZG90IDwtIGRvW2RhLnJhbmdlLCAxXSAjIGRhdGEgdGltZQpkbyA8LSBkb1tkYS5yYW5nZSwgLTFdICMgc3Vic2V0IG9mIGRhdGEgd2l0aG91dCB0Cm5kbyA8LSBucm93KGRvKQpuaW4gPC0gbmRvIC0gbm91dCAjIGxpYnJhcnkgc2FtcGxlIHNpemUKYGBgClN0YW5kYXJkaXphdGlvbgpgYGB7cn0KIyBJbi1zYW1wbGUKZG8ubWVhbiA8LSBhcHBseShkb1sxOm5pbiwgXSwgMiwgbWVhbiwgbmEucm0gPSBUKSAgIyBtZWFuIGFidW5kYW5jZSBpbiBpbi1zYW1wbGUKZG8uc2QgPC0gYXBwbHkoZG9bMTpuaW4sIF0sIDIsIHNkLCBuYS5ybSA9IFQpICAgICAgIyBTRCBvZiBhYnVuZGFuY2UgaW4gaW4tc2FtcGxlCmQgPC0gZG9bMToobmluLTEpLCBdICAgICAgICAgICAgICAgICAgICAgICAgICAjIEluLXNhbXBsZSBkYXRhc2V0IGF0IHRpbWUgdApkX3RwMSA8LSBkb1syOihuaW4pLCBdICAgICAgICAgICAgICAgICAgICAgICAgIyBJbi1zYW1wbGUgZGF0YXNldCBhdCB0aW1lIHQrMQpkcyA8LSAoZCAtIHJlcG1hdChkby5tZWFuLCBucm93KGQpLCAxKSkqcmVwbWF0KGRvLnNkLCBucm93KGQpLCAxKSBeIC0xICMgTm9ybWFsaXplZCBpbi1zYW1wbGUgZGF0YXNldCBhdCB0aW1lIHQKZHNfdHAxIDwtIChkX3RwMSAtIHJlcG1hdChkby5tZWFuLCBucm93KGRfdHAxKSwgMSkpKnJlcG1hdChkby5zZCwgbnJvdyhkX3RwMSksIDEpIF4gLTEgIyBOb3JtYWxpemVkIGluLXNhbXBsZSBkYXRhc2V0IGF0IHRpbWUgdCsxCgojIE91dC1zYW1wbGUKaWYob3V0LnNhbXBsZSAmIG5vdXQgIT0gMCl7CiAgZC50ZXN0IDwtIGRvW25pbjoobmRvIC0gMSksIF0gICAgICAgICAgICAgICAgICMgT3V0LW9mLXNhbXBsZSBkYXRhc2V0IGF0IHRpbWUgdCAKICBkdF90cDEgPC0gZG9bKG5pbiArIDEpOiBuZG8sIF0gICAgICAgICAgICAgICAgICMgT3V0LW9mLXNhbXBsZSBkYXRhc2V0IGF0IHRpbWUgdCsxCiAgZHMudGVzdCA8LSAoZC50ZXN0IC0gcmVwbWF0KGRvLm1lYW4sIG5yb3coZC50ZXN0KSwgMSkpKnJlcG1hdChkby5zZCwgbnJvdyhkLnRlc3QpLCAxKSBeIC0xICMgTm9ybWFsaXplZCBvdXQtb2Ytc2FtcGxlIGRhdGFzZXQgYXQgdGltZSB0CiAgZHN0X3RwMSA8LSAoZHRfdHAxIC0gcmVwbWF0KGRvLm1lYW4sIG5yb3coZHRfdHAxKSwgMSkpKnJlcG1hdChkby5zZCwgbnJvdyhkdF90cDEpLCAxKSBeIC0xICMgTm9ybWFsaXplZCBvdXQtb2Ytc2FtcGxlIGRhdGFzZXQgYXQgdGltZSB0KzEKfWVsc2V7ZC50ZXN0IDwtIGR0X3RwMSA8LSBkcy50ZXN0IDwtIE5VTEx9CgojIENvbXBpbGVkIGRhdGEgYXQgdGltZSB0IApkcy5hbGwgPC0gcmJpbmQoZHMsIGRzLnRlc3QpCmhlYWQoZHMuYWxsKQpgYGAKSW5pdGlhbGl6YXRpb24gb2YgcHNldWRvLXJhbmRvbSBudW1iZXIgZ2VuZXJhdG9yCmBgYHtyfQpzZWVkIDwtIDQ5NTYzCnNldC5zZWVkKHNlZWQpCmBgYAoKCiMjIyMgWzQuMl0gT3B0aW1hbCBlbWJlZGRpbmcgZGltZW5zaW9uCkZpbmQgdGhlIG9wdGltYWwgZW1iZWRkaW5nIGRpbWVuc2lvbiwgYmFzZWQgb24gdW5pdmFyaWF0ZSBzaW1wbGV4IHByb2plY3Rpb24KYGBge3Igd2FybmluZyA9IEZBTFNFfQpFbWF4IDwtIDQgIyBlcXVhbCB0byBvciBzbWFsbGVyIHRoYW4gdGhlIG51bWJlciBvZiBub2RlcyAoZGltZW5zaW9uIG9mIHRoZSBERSBzeXN0ZW0pCmNyaSA8LSAncm1zZScgIyBtb2RlbCBzZWxlY3Rpb24gCkVkIDwtIE5VTEwKZm9yZWNhc3Rfc2tpbGxfc2ltcGxleCA8LSBOVUxMCmZvcihpIGluIDE6bmNvbChkcykpewogIHNweC5pIDwtIHNpbXBsZXgoZHNbLCBpXSwgRSA9IDI6RW1heCkKICBFZCA8LSBjKEVkLCBzcHguaVt3aGljaC5taW4oc3B4LmlbLCBjcmldKVsxXSwgJ0UnXSkKICBmb3JlY2FzdF9za2lsbF9zaW1wbGV4IDwtIGMoZm9yZWNhc3Rfc2tpbGxfc2ltcGxleCwgc3B4Lmlbd2hpY2gubWluKHNweC5pWywgY3JpXSlbMV0sICdyaG8nXSkKfQpFZCAjIFRoZSBvcHRpbWFsIGVtYmVkZGluZyBkaW1lbnNpb24gZm9yIGVhY2ggdmFyaWFibGUKYGBgCk9wdGltYWwgZW1iZWRkaW5nIGRpbWVuc2lvbiBhbmQgZm9yZWNhc3Rpbmcgc2tpbGwKYGBge3J9CkVkCmZvcmVjYXN0X3NraWxsX3NpbXBsZXgKCmBgYAojIyMjIFs0LjNdIENDTSBhbmFseXNpcwoqIEZpbmQgY2F1c2FsIHZhcmlhYmxlcyBieSBDQ00gYW5hbHlzaXMgdGhhdCB3aWxsIGJlIHVzZWQgZm9yIG11bHRpdmlldyBlbWJlZGRpbmcuCgoqIFdhcm5pbmc6IEl0IGlzIHRpbWUgY29uc3VtaW5nIGZvciBjYWxjdWxhdGluZyB0aGUgY2F1c2F0aW9uIGZvciBlYWNoIG5vZGUKCiogQ0NNIGNhdXNhbGl0eSB0ZXN0IGZvciBhbGwgbm9kZSBwYWlycyAodGhlIGZ1bmN0aW9uIHdhcyB1cGRhdGVkIGF0IDIwMjQvMDUvMDcpCmBgYHtyIHdhcm5pbmcgPSBGQUxTRX0KY2NtLm91dCA8LSBjY20uZmFzdC5kZW1vKGRzLCBFcGFpciA9IFQsIGNyaSA9IGNyaSwgRW1heCA9IEVtYXgpCmNjbS5zaWcgPC0gY2NtLm91dFtbJ2NjbS5zaWcnXV0KY2NtLnJobyA8LSBjY20ub3V0W1snY2NtLnJobyddXQojVG8gYXZvaWQgb3ZlcndyaXRlIHRoZSBvcmlnaW5hbCBmaWxlcywgd2Ugc2F2ZSB0aGVtIHdpdGggZGlmZmVyZW50IG5hbWVzLGlkZW50aWZpZWQgYnkgZGF0ZS4KREFZID0gU3lzLkRhdGUoKQpzYXZlUkRTKGNjbS5zaWcsIHBhc3RlKCdjY21fc2lnJywgZGEubmFtZSwnbmluJywgbmluLCBEQVksICcub2JqJywgc2VwID0gJ18nKSkKc2F2ZVJEUyhjY20ucmhvLCBwYXN0ZSgnY2NtX3JobycsIGRhLm5hbWUsJ25pbicsIG5pbiwgREFZLCAnZGVtby5vYmonLCBzZXAgPSAnXycpKQpgYGAKSnVzdCBpbiBjYXNlIG5vdCBjb25kdWN0aW5nIENDTSBidXQganVzdCBsb2FkaW5nIHRoZSByZXN1bHQgb2YgQ0NNIGF0IDIwMjQvMDcvMjkKYGBge3J9CkRBWSA9ICIyMDI0LTA3LTI5IgpjY20uc2lnX29sZCA8LSByZWFkUkRTKHBhc3RlKCdjY21fc2lnJywgZGEubmFtZSwnbmluJywgbmluLCBEQVksICcub2JqJywgc2VwID0gJ18nKSkgCmNjbS5yaG9fb2xkIDwtIHJlYWRSRFMocGFzdGUoJ2NjbV9yaG8nLCBkYS5uYW1lLCduaW4nLCBuaW4sIERBWSwgJ2RlbW8ub2JqJywgc2VwID0gJ18nKSkKYGBgCgpgYGB7cn0KY2NtLnNpZwpjY20ucmhvCmBgYAojIyMjIFs0LjRdIE11bHRpdmlldyBkaXN0YW5jZQojIyMjIyBbNC40LjFdIFBlcmZvcm1pbmcgbXVsdGl2aWV3IGFuYWx5c2lzCkJhc2VkIG9uIHRoZSBjYXVzYWwgdmFyaWFibGVzIGRldGVjdGVkIGluIENDTSwKCigxKSBnZW5lcmF0ZXMgdGhlIHRpbWUgbGFnIHNlcmllcyAod2l0aCBtYXhpbXVtIGxhZyA9IDMpLAoKKDIpIGNvbmR1Y3QgbXVsdGl2YXJpYXRlIHNpbXBsZXggcHJvamVjdGlvbiBhbmQgZXZhbHVhdGUgdGhlIGZvcmVjYXN0IHNraWxsLCBhbmQKCigzKSBzZWxlY3RlZCB0aGUgYmVzdCBrbig9MTAwKSBTU1IuCgpQZXJmb3JtIG11bHRpdmlldyBlbWJlZGRpbmcgYW5hbHlzaXMgZm9yIGVhY2ggbm9kZQoKV2FybmluZzogSXQgaXMgdGltZSBjb25zdW1pbmcgZm9yIHJ1bm5pbmcgbXVsdGl2aWV3IGVtYmVkZGluZyBmb3IgZWFjaCBub2RlcwpgYGB7ciB3YXJuaW5nID0gRkFMU0V9CmVzZWxlX2xhZyA8LSBlc2ltLmxhZy5kZW1vKGRzLCBjY20ucmhvLCBjY20uc2lnLCBFZCwga21heCA9IDEwMDAwLCBrbiA9IDEwMCwgbWF4X2xhZyA9IDMsIEVtYXggPSBFbWF4KQojIFRvIGF2b2lkIG92ZXJ3cml0ZSB0aGUgb3JpZ2luYWwgZmlsZXMsIHdlIHNhdmUgdGhlbSB3aXRoIGRpZmZlcmVudCBuYW1lcywgJ1hYWF9ORVcnLgpEQVkgPSBTeXMuRGF0ZSgpCnNhdmVSRFMoZXNlbGVfbGFnLCBwYXN0ZSgnZXNlbGVMYWcnLCBkYS5uYW1lLCAnbmluJywgbmluLCBEQVksICdkZW1vLm9iaicsIHNlcD0nXycpKQpgYGAKVGhlIGxpc3Qgb2YgdGhlIHNlbGVjdGVkIGJlc3QgbXVsdGl2YXJpYXRlIFNTUnMgZm9yIGVhY2ggbm9kZSAoc3BlY2llcywgc3ApIHdpdGgKCigxKSB0aGUgY29ycmVsYXRpb24gY29lZmZpY2llbnQgKHJobykKCigyKSB0aGUgbGlzdCBvZiB2YXJpYWJsZXMgKFhfMSwgWF8yLCDigKYpIHVzZWQgaW4gZWFjaCBTU1IsIG5vdGluZyB0aGF0IHRoZSBudW1iZXIgb2YgdmFyaWFibGVzIGlzIGlkZW50aWNhbCB0byB0aGUgb3B0aW1hbCBlbWJlZGRpbmcgZGltZW5zaW9uIG9idGFpbmVkIGluIFsyLjFdLCBhbmQKCigzKSB0aGUgbGlzdCBvZiB0aW1lIGxhZ3MgKHZsYWdfMSwgdmxhZ18yLCDigKYpIHVzZWQgaW4gdGhlIGNvcnJlc3BvbmRpbmcgdmFyaWFibGVzIChYXzEsIFhfMiwg4oCmKS4KYGBge3J9CmFzLmRhdGEuZnJhbWUoZXNlbGVfbGFnKQpgYGAKCiMjIyMjIFs0LjQuMl0gQ29tcHV0ZSBtdWx0aXZpZXcgZGlzdGFuY2UKYGBge3J9CmRtYXRyaXgubXYgPC0gbXZkaXN0LmRlbW8oZHMsIGRzLmFsbCwgZXNlbGVfbGFnKQpkbWF0cml4LnRyYWluLm12eCA8LSBkbWF0cml4Lm12W1snZG1hdHJpeC50cmFpbi5tdngnXV0KZG1hdHJpeC50ZXN0Lm12eCA8LSBkbWF0cml4Lm12W1snZG1hdHJpeC50ZXN0Lm12eCddXQpgYGAKTGVhdmUtb25lLW91dCBjcm9zcy12YWxpZGF0aW9uIGZvciBmaW5kaW5nIHRoZSBvcHRpbWFsIHBhcmFtZXRlcnMgZm9yIE1EUiBTLW1hcCBhbmFseXNpcwoK4oCTV2FybmluZzogVGhlIGNyb3NzLXZhbGlkYXRpb24gaXMgdGhlIG1vc3QgdGltZS1jb25zdW1pbmcgc3RlcCBpbiBNRFIgUy1tYXAgcmVxdWlyaW5nIG1hc3NpdmUgY29tcHV0YXRpb25zIGFuZCAuIFRodXMsIHdlIHJlY29tbWVuZCBkaXZpZGluZyBqb2IgaW50byBzbWFsbGVyIHBhcnRzIChzdWIuZGE+MSkgb3IgdXNlZCBwYXJhbGxlbCBjb21wdXRhdGlvbiAocGFyYWxsPVQsIG5jb3JlPj0xKQpgYGB7cn0KZG8uTURSLkNWIDwtIFQKIyMjIFRoZSBwYXJhbWV0ZXIgY3YudW5pdCBkZXRlcm1pbmVzIHRoZSBwcmVjaXNpb24gb2Ygc2VsZWN0ZWQgcGFyYW1ldGVycyBhbmQgc3Ryb25nbHkgaW5mbHVlbmNlcyBjb21wdXRhdGlvbiB0aW1lLgojIyMgSW4gb3VyIGNhc2VzLCB3ZSB1c2VkIGN2LnVuaXQ9MC4wMjUgdG8gb2J0YWluIG1vcmUgcHJlY2lzZSBlc3RpbWF0aW9ucwojIyMgVGhpcyBwYXJhbWV0ZXIgbWF5IGJlIGFkanVzdGVkIHRvIDAuMDUgb3IgZXZlbiAwLjEsIGRlcGVuZGluZyBvbiBob3cgc2Vuc2l0aXZlIHRoZSByZXN1bHRzIHRvIHBhcmFtZXRlciBwcmVjaXNpb24uIApjdi51bml0IDwtIDAuMDI1CmFscGhhLnNvIDwtIHNlcSgwLCAxLCBjdi51bml0KTsgICAgICAgICAgICAjIFNlcXVlbmNlIG9mIGFscGhhCnN1Yi5kYSA8LSAxICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAjIERpdmlkZSB0aGUgY29tcHV0YXRpb24gam9iIGludG8gZml2ZSBwYXJ0cyAKYWZzcCA8LSBlcXNwbGl0KDE6bGVuZ3RoKGFscGhhLnNvKSwgc3ViLmRhKSAjIERpdmlkZSB0aGUgcGFyYW1ldGVyIHNwYWNlIGJhc2VkIG9uIGFscGhhIHBhcmFtZXRlcgphbGYgPC0gMSAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgIyBSdW4gQ1YgaW4gdGhlIGZpcnN0IHBhcmFtZXRlciBzdWJzZXQgCgojIENyb3NzLXZhbGlkYXRpb24gb2YgTURSIGFuYWx5c2lzICAgIAppZihkby5NRFIuQ1YpewogIGFscGhhLnMgPC0gYWxwaGEuc29bYWZzcFthbGYsIDFdOmFmc3BbYWxmLCAyXV0gIyBTdWJzZXQgcGFyYW1ldGVyIHNwYWNlCiAgY3YuaW5kIDwtIGN2Lk1EUi5kZW1vKGRzLCBkc190cDEsIGRtYXRyaXgubGlzdCA9IGRtYXRyaXgudHJhaW4ubXZ4LCAKICAgICAgICAgICAgICAgICAgICAgICAgcGFyYWxsID0gVCwgbmNvcmUgPSAyNCwga2VlcF9pbnRyYSA9IFQsYWxwaGEuc2VxID0gYWxwaGEucykKICAjIFRvIGF2b2lkIG92ZXJ3cml0ZSB0aGUgb3JpZ2luYWwgZmlsZXMsIHdlIHNhdmUgdGhlbSB3aXRoIGRpZmZlcmVudCBuYW1lcywgJ1hYWF9ORVcnLgogIHNhdmVSRFMoY3YuaW5kLCBwYXN0ZShkYS5uYW1lLCAnbmluJywgbmluLCAnY3Z1bml0JywgY3YudW5pdCwgJ2FscGgnLCBhbHBoYS5zWzFdKjEwMCwgREFZLCAnY3ZvdXRfTm12eF9SYWxseC5vYmonLCBzZXAgPSAnXycpKQp9CmBgYAoKIyMjIyMgWzQuNC4zXSBTZWxlY3RpbmcgdGhlIG9wdGltYWwgcGFyYW1ldGVycwpTZWxlY3QgdGhlIG9wdGltYWwgcGFyYW1ldGVyIHNldCBmb3IgcmVndWxhcml6ZWQgcmVncmVzc2lvbiBtb2RlbCB3aXRoIHRoZSBtaW5pbWFsIE1TRQoKYGBge3J9CnBhcmFjdi5kZW1vIDwtIHNlY3YuZGVtbyhjdi5pbmQpCnBhcmFjdi5kZW1vCmBgYAojIyMjIFs0LjVdIE1EUiBTLW1hcApGaXR0aW5nIE1EUiBTLW1hcCBiYXNlZCBvbiB0aGUgcGFyYW1ldGVycyBzZWxlY3RlZCBieSBDVgoKTm90ZSB0aGF0IHRoZSBsaW5lYXIgcmVncmVzc2lvbiBtb2RlbCBpbiBNRFIgUy1tYXAgaW5jbHVkZXMgYWxsIG9mIHZhcmlhYmxlcyBhcyBYIGV2ZW4gaWYgc29tZSBvZiB0aGVtIHdlcmUgbm90IHNlbGVjdGVkIGFzIHRoZSBjYXVzYWwgdmFyaWFibGVzIGF0IHRoZSBzdGVwIG9mIHVzaW5nIENDTS4gVGhpcyBpcyByZWFzb25hYmxlIGJlY2F1c2UgUy1tYXAgY29lZmZpY2llbnRzIHJlcHJlc2VudCB0aGUgZWZmZWN0cyBvZiB2YXJpYWJsZXMgYXQgc2hvcnQgdGltZXNjYWxlIHdoaWxlIENDTSBldmFsdWF0ZXMgdGhlIGNhdXNhbGl0eSBpbiB0aGUgd2hvbGUgcGVyaW9kIG9mIHRoZSB0aW1lIHNlcmllcy4gCmBgYHtyfQojU2V0dGluZwpkby5NRFIgPC0gRgpjdi51bml0IDwtIDAuMDI1ICAgICAgICAgICAgICAgICAgICAgICAgICAgCnB0eXBlIDwtICdhZW5ldCcgICAgICAgICAgI2VuZXQ6ZWxhc3RpYy1uZXQgb3IgbXNhZW5ldDogYWRhcHRpdmUgZWxhc3RpYy1uZXQKCiNGaXR0aW5nIHRoZSBNRFIgUy1tYXAKc21hcC4ySDJQIDwtIE1EUnNtYXAuZGVtbyhwYXJhY3YgPSBwYXJhY3YuZGVtbywgcHR5cGUgPSBwdHlwZSwga2VlcF9pbnRyYSA9IFQsIG91dC5zYW1wbGUgPSBULAogICAgICAgICAgICAgICAgICAgICAgICAgICAgZHMsZHNfdHAxLGRzLnRlc3QsZHN0X3RwMSwKICAgICAgICAgICAgICAgICAgICAgICAgICAgIGRtYXRyaXgubGlzdCA9IGRtYXRyaXgudHJhaW4ubXZ4LAogICAgICAgICAgICAgICAgICAgICAgICAgICAgZG1hdHJpeC50ZXN0Lmxpc3QgPSBkbWF0cml4LnRlc3QubXZ4KQpgYGAKCkluIGNhc2UgZm9yIHNhdmluZyB0aGUgcmVzdWx0cwpgYGB7cn0KREFZID0gU3lzLkRhdGUoKQpuci5vdXQgPC0gc21hcC4ySDJQW1snbnIub3V0J11dOwoKICBzYXZlUkRTKG5yLm91dCwgcGFzdGUoZGEubmFtZSwnX25pbicsIG5pbiwgJ2N2dW5pdCcsIGN2LnVuaXQsIHB0eXBlLCBEQVksICducm91dF9ObXZ4X1JhbGx4X2RlbW9fTkVXLm9iaicsc2VwID0gJ18nKSkKICAgICMgU2F2ZSBpbnRlcmFjdGlvbiBKYWNvYmlhbiBtYXRyaWNlcyBhdCBhbGwgdGltZSBwb2ludHMKICBzYXZlUkRTKHNtYXAuMkgyUFtbJ2pjb2YnXV0sIHBhc3RlKGRhLm5hbWUsJ25pbicsIG5pbiwgJ2N2dW5pdCcsIGN2LnVuaXQsIHB0eXBlLCBEQVksICdfamNvZl9ObXZ4X1JhbGx4X2RlbW9fTkVXLm9iaicsIHNlcD0nXycpKQoKYGBgCgpTLW1hcCBjb2VmZmljaWVudHMKYGBge3J9CnNtYXAuMkgyUFtbJ2pjb2YnXV0KYGBgCiMjIyMgWzQuNl0gQ29tcGFyZSBTLW1hcCBjb2VmZmljaWVudHMgYW5kIHRoZW9yZXRpY2FsIGJlbmNobWFyawpMb2FkaW5nIGRhdGEKYGBge3J9CnNtYXAuMkgyUCA8LSBsaXN0KCkKc21hcC4ySDJQW1snamNvZiddXSA8LSByZWFkUkRTKCI0cF9tb2RlbF9uaW5fMTk4X2N2dW5pdF8wLjAyNV9hZW5ldF8yMDI0LTA3LTMxX19qY29mX05tdnhfUmFsbHhfZGVtb19ORVcub2JqIikKc21hcC4ySDJQW1snamNvZiddXQpgYGAKIyMjIyMgWzQuNi4xXSBDb21wYXJlIG11bHRpdmFyaWF0ZSBTLW1hcCBhbmQgTURSIFMtbWFwCmBgYHtyfQpmaW5hbF9JRCA8LSAyMDAKZGVsdGFfMTEgPC0gMQoKTURSX1NtYXBfZEgxZEgxIDwtIHN1YnNldChzbWFwLjJIMlBbWydqY29mJ11dLCB2YXJpYWJsZSA9PSBqX0hvc3QxKVsxOjE5OSwgNV0gLSBkZWx0YV8xMQpNRFJfU21hcF9kSDFkSDIgPC0gc3Vic2V0KHNtYXAuMkgyUFtbJ2pjb2YnXV0sIHZhcmlhYmxlID09IGpfSG9zdDEpWzE6MTk5LCA2XQpNRFJfU21hcF9kSDFkUDEgPC0gc3Vic2V0KHNtYXAuMkgyUFtbJ2pjb2YnXV0sIHZhcmlhYmxlID09IGpfSG9zdDEpWzE6MTk5LCA3XQpNRFJfU21hcF9kSDFkUDIgPC0gc3Vic2V0KHNtYXAuMkgyUFtbJ2pjb2YnXV0sIHZhcmlhYmxlID09IGpfSG9zdDEpWzE6MTk5LCA4XQoKcGxvdChIUF9yZXN1bHQkdFstZmluYWxfSURdLCBIUF9tX3NtYXBfcmVzMl9zJHNtYXBfY29lZmZpY2llbnRzW1sxXV0kY18xWy1maW5hbF9JRF0gLSBkZWx0YV8xMSwgdHlwZSA9ICJsIiwgY29sID0gMSwgeWxpbSA9IGMoLTAuOSwgMS4wKSwgeGxhYiA9ICJ0aW1lIiwgeWxhYiA9ICJJbnRlcmF0aW9uIGNvZWZmaWNpZW50cyIpCnBhcihuZXcgPSBUKQpwbG90KEhQX3Jlc3VsdCR0Wy1maW5hbF9JRF0sIEhQX21fc21hcF9yZXMyX3Mkc21hcF9jb2VmZmljaWVudHNbWzFdXSRjXzJbLWZpbmFsX0lEXSwgdHlwZSA9ICJsIiwgY29sID0gInJlZCIsIHlsaW0gPSBjKC0wLjksIDEuMCksIHhsYWIgPSAiIiwgeWxhYiA9ICIiKQpwYXIobmV3ID0gVCkKcGxvdChIUF9yZXN1bHQkdFstZmluYWxfSURdLCBIUF9tX3NtYXBfcmVzMl9zJHNtYXBfY29lZmZpY2llbnRzW1sxXV0kY18zWy1maW5hbF9JRF0sIHR5cGUgPSAibCIsIGNvbCA9ICJibHVlIiwgeWxpbSA9IGMoLTAuOSwgMS4wKSwgeGxhYiA9ICIiLCB5bGFiID0gIiIpCnBhcihuZXcgPSBUKQpwbG90KEhQX3Jlc3VsdCR0Wy1maW5hbF9JRF0sIEhQX21fc21hcF9yZXMyX3Mkc21hcF9jb2VmZmljaWVudHNbWzFdXSRjXzRbLWZpbmFsX0lEXSwgdHlwZSA9ICJsIiwgY29sID0gImdyZWVuIiwgeWxpbSA9IGMoLTAuOSwgMS4wKSwgeGxhYiA9ICIiLCB5bGFiID0gIiIpCnBhcihuZXcgPSBUKQpwbG90KEhQX3Jlc3VsdCR0Wy1maW5hbF9JRF0sIE1EUl9TbWFwX2RIMWRIMSwgdHlwZSA9ICJsIiwgY29sID0gImJyb3duIiwgeWxpbSA9IGMoLTAuOSwgMS4wKSwgeGxhYiA9ICIiLCB5bGFiID0gIiIpCnBhcihuZXcgPSBUKQpwbG90KEhQX3Jlc3VsdCR0Wy1maW5hbF9JRF0sIE1EUl9TbWFwX2RIMWRQMSwgdHlwZSA9ICJsIiwgY29sID0gImN5YW4iLCB5bGltID0gYygtMC45LCAxLjApLCB4bGFiID0gIiIsIHlsYWIgPSAiIikKCmxlZ2VuZCgidG9wcmlnaHQiLCAKICAgICAgICAgIGxlZ2VuZCA9IGMoIlMtbWFwIGZyb20gSDEgdG8gSDEgLSBkZWx0YTExIiwgIlMtbWFwIGZyb20gSDIgdG8gSDEiLCAiUy1tYXAgZnJvbSBQMSB0byBIMSIsICJTLW1hcCBmcm9tIFAyIHRvIEgxIiwiTURSIFMtbWFwIGZyb20gSDEgdG8gSDEgLSBkZWx0YTExIiwgIk1EUiBTLW1hcCBmcm9tIFAxIHRvIEgxIiksICAKICAgICAgICAgIGNvbCA9IGMoImJsYWNrIiwgInJlZCIsICJibHVlIiwgImdyZWVuIiwgImJyb3duIiwgImN5YW4iKSwgCiAgICAgICAgICBsdHkgPSBjKDEsIDEsIDEsIDEsIDEsIDEpLCAgICAgICAgICAgICAgCiAgICAgICAgICBjZXggPSAwLjgpICAgCmBgYAojIyMjIyBbNC42LjJdIExpc3Qgb2YgdGhlb3JldGljYWwgSmFjb2JpYW4KClxbClxmcmFje1xwYXJ0aWFsIEZfe0gsaX19e1xwYXJ0aWFsIEhfe2ksa319ID0gLTEgKyAoMSAtIGFfaSBIX2kpIGUgXiB7LWFfaSBIX2kgLSBjX3sxaX0gUF8xIC0gY197Mml9IFBfMn0gKHJfaSArIGUgXnstbV97SCxpfX0pClxdClxbClxmcmFje1xwYXJ0aWFsIEZfe0gsaX19e1xwYXJ0aWFsIEhfe2knLGt9fSA9IDAgClxdClxbClxmcmFje1xwYXJ0aWFsIEZfe0gsaX19e1xwYXJ0aWFsIFBfe2osa319ID0gY197aml9IGUgXiB7LWFfaSBIX2kgLSBjX3sxaX0gUF8xIC0gY197Mml9IFBfMn0gKC1yX2kgLSBlIF4gey1tX3tILGl9fSkgSF9rClxdCgoKRnVuY3Rpb25zIGZvciBwYXJ0aWFsIGRlcml2YXRpdmVzIGZvciBIMToKYGBge3J9CmRGX0gxZEgxIDwtIGZ1bmN0aW9uKGRhdGEpIHsKICBjb2VmZiA8LSAtMSArICgxIC0gYTEgKiBkYXRhJEgxKSAqIGV4cCgtIGExICogZGF0YSRIMSAtIGMxMSAqIGRhdGEkUDEgLSBjMjEgKiBkYXRhJFAyKSAqIChyMSArIGV4cCgtIG1IMSkpCiAgCiAgcmV0dXJuKGNvZWZmKQp9CgpkRl9IMWRQMSA8LSBmdW5jdGlvbihkYXRhKSB7CiAgY29lZmYgPC0gYzExICogZXhwKC0gYTEgKiBkYXRhJEgxIC0gYzExICogZGF0YSRQMSAtIGMyMSAqIGRhdGEkUDIpICogKC0gcjEgLSBleHAoLSBtSDEpKSAqIGRhdGEkSDEKICAKICByZXR1cm4oY29lZmYpCn0gIAoKZEZfSDFkUDIgPC0gZnVuY3Rpb24oZGF0YSkgewogIGNvZWZmIDwtIGMyMSAqIGV4cCgtIGExICogZGF0YSRIMSAtIGMxMSAqIGRhdGEkUDEgLSBjMjEgKiBkYXRhJFAyKSAqICgtIHIxIC0gZXhwKC0gbUgxKSkgKiBkYXRhJEgxCiAgCiAgcmV0dXJuKGNvZWZmKQp9CmBgYAoKIyMjIyMgWzQuNi4zXSBDb21wYXJpc29uIGZvciB0aGUgZGlhZ29uYWwgZWxlbWVudCAoRmlnLiAyYWI6IEgxIC0+IEgxKTogZ2dwbG90CgpEYXRhZnJhbWUgZm9yIGdncGxvdApgYGB7cn0KI0ZvciBsaW5lcGxvdHMKSDJQMl9IMXRvSDFfZ2dwbG90IDwtIGRhdGEuZnJhbWUoCiAgdGltZSA9IEhQX3Jlc3VsdCR0Wy1maW5hbF9JRF0sCiAgSW50UyA9IEhQX21fc21hcF9yZXMyX3Mkc21hcF9jb2VmZmljaWVudHNbWzFdXSRjXzFbLWZpbmFsX0lEXSAtIGRlbHRhXzExLAogIHR5cGUgPSByZXAoIjAxc3RkX3NtYXBIMXRvSDEiLCAxOTkpCikKSDJQMl9IMXRvSDFfZ2dwbG90IDwtIHJiaW5kLmRhdGEuZnJhbWUoCiAgSDJQMl9IMXRvSDFfZ2dwbG90LCBkYXRhLmZyYW1lKAogICAgdGltZSA9IEhQX3Jlc3VsdCR0Wy1maW5hbF9JRF0sCiAgICBJbnRTID0gTURSX1NtYXBfZEgxZEgxLAogICAgdHlwZSA9IHJlcCgiMDJtZHJfc21hcEgxdG9IMSIsIDE5OSkKICApCikKSDJQMl9IMXRvSDFfZ2dwbG90IDwtIHJiaW5kLmRhdGEuZnJhbWUoCiAgSDJQMl9IMXRvSDFfZ2dwbG90LCBkYXRhLmZyYW1lKAogICAgdGltZSA9IEhQX3Jlc3VsdCR0Wy1maW5hbF9JRF0sCiAgICBJbnRTID0gZEZfSDFkSDEoSFBfcmVzdWx0KVstZmluYWxfSURdLAogICAgdHlwZSA9IHJlcCgiMDNJU19kSDFkSDEiLCAxOTkpCiAgKQopCiAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgCkgyUDJfUDF0b0gxX2dncGxvdCA8LSBkYXRhLmZyYW1lKAogIHRpbWUgPSBIUF9yZXN1bHQkdFstZmluYWxfSURdLAogIEludFMgPSBIUF9tX3NtYXBfcmVzMl9zJHNtYXBfY29lZmZpY2llbnRzW1sxXV0kY18zWy1maW5hbF9JRF0sCiAgdHlwZSA9IHJlcCgiMDFzdGRfc21hcFAxdG9IMSIsIDE5OSkKKQpIMlAyX1AxdG9IMV9nZ3Bsb3QgPC0gcmJpbmQuZGF0YS5mcmFtZSgKICBIMlAyX1AxdG9IMV9nZ3Bsb3QsIGRhdGEuZnJhbWUoCiAgICB0aW1lID0gSFBfcmVzdWx0JHRbLWZpbmFsX0lEXSwKICAgIEludFMgPSBNRFJfU21hcF9kSDFkUDEsCiAgICB0eXBlID0gcmVwKCIwMm1kcl9zbWFwUDF0b0gxIiwgMTk5KQogICkKKQpIMlAyX1AxdG9IMV9nZ3Bsb3QgPC0gcmJpbmQuZGF0YS5mcmFtZSgKICBIMlAyX1AxdG9IMV9nZ3Bsb3QsIGRhdGEuZnJhbWUoCiAgICB0aW1lID0gSFBfcmVzdWx0JHRbLWZpbmFsX0lEXSwKICAgIEludFMgPSBkRl9IMWRQMShIUF9yZXN1bHQpWy1maW5hbF9JRF0gKiBIUF9yZXN1bHQuc2RbM10gLyBIUF9yZXN1bHQuc2RbMV0sCiAgICB0eXBlID0gcmVwKCIwM0lTX2RIMWRQMSIsIDE5OSkKICApCikKCgojRm9yIGVycm9yIHBsb3RzCkgyUDJfZXJyb3JfSDF0b0gxX2dncGxvdCA8LSBkYXRhLmZyYW1lKAogIHRpbWUgPSBIUF9yZXN1bHQkdFstZmluYWxfSURdLAogIEludFMgPSBIUF9tX3NtYXBfcmVzMl9zJHNtYXBfY29lZmZpY2llbnRzW1sxXV0kY18xWy1maW5hbF9JRF0gLSBkZWx0YV8xMSAtIGRGX0gxZEgxKEhQX3Jlc3VsdClbLWZpbmFsX0lEXSwKICB0eXBlID0gcmVwKCIwMXN0ZF9zbWFwSDF0b0gxIiwgMTk5KQopCkgyUDJfZXJyb3JfSDF0b0gxX2dncGxvdCA8LSByYmluZC5kYXRhLmZyYW1lKAogIEgyUDJfZXJyb3JfSDF0b0gxX2dncGxvdCwgZGF0YS5mcmFtZSgKICAgIHRpbWUgPSBIUF9yZXN1bHQkdFstZmluYWxfSURdLAogICAgSW50UyA9IE1EUl9TbWFwX2RIMWRIMSAtIGRGX0gxZEgxKEhQX3Jlc3VsdClbLWZpbmFsX0lEXSwKICAgIHR5cGUgPSByZXAoIjAybWRyX3NtYXBIMXRvSDEiLCAxOTkpCiAgKQopCgpIMlAyX2Vycm9yX1AxdG9IMV9nZ3Bsb3QgPC0gZGF0YS5mcmFtZSgKICB0aW1lID0gSFBfcmVzdWx0JHRbLWZpbmFsX0lEXSwKICBJbnRTID0gSFBfbV9zbWFwX3JlczJfcyRzbWFwX2NvZWZmaWNpZW50c1tbMV1dJGNfM1stZmluYWxfSURdIC0gZEZfSDFkUDEoSFBfcmVzdWx0KVstZmluYWxfSURdICogSFBfcmVzdWx0LnNkWzNdIC8gSFBfcmVzdWx0LnNkWzFdLAogIHR5cGUgPSByZXAoIjAxc3RkX3NtYXBQMXRvSDEiLCAxOTkpCikKSDJQMl9lcnJvcl9QMXRvSDFfZ2dwbG90IDwtIHJiaW5kLmRhdGEuZnJhbWUoCiAgSDJQMl9lcnJvcl9QMXRvSDFfZ2dwbG90LCBkYXRhLmZyYW1lKAogICAgdGltZSA9IEhQX3Jlc3VsdCR0Wy1maW5hbF9JRF0sCiAgICBJbnRTID0gTURSX1NtYXBfZEgxZFAxIC0gZEZfSDFkUDEoSFBfcmVzdWx0KVstZmluYWxfSURdICogSFBfcmVzdWx0LnNkWzNdIC8gSFBfcmVzdWx0LnNkWzFdLAogICAgdHlwZSA9IHJlcCgiMDJtZHJfc21hcFAxdG9IMSIsIDE5OSkKICApCikKYGBgCgpgYGB7cn0KZmlnMmFfZ2dwbG90IDwtIGdncGxvdChkYXRhID0gSDJQMl9IMXRvSDFfZ2dwbG90KSArCiAgc2NhbGVfY29sb3VyX21hbnVhbCh2YWx1ZXMgPSBjKCIjZmY0YjAwIiwgIiM0ZGM0ZmYiLCAiI2Y2YWEwMCIpKSArCiAgc2NhbGVfc2hhcGVfbWFudWFsKHZhbHVlcyA9IGMoMTUsIDE2LCAxNykpICsK44CAZ2VvbV9saW5lKGFlcyh4ID0gdGltZSwgeSA9IEludFMsIGdyb3VwID0gdHlwZSwgY29sb3IgPSB0eXBlKSkgKwogIGdlb21fcG9pbnQoYWVzKHggPSB0aW1lLCB5ID0gSW50UywgY29sb3IgPSB0eXBlLCBzaGFwZSA9IHR5cGUpLCBzaXplID0gMikgKwogIHhsaW0oMTgwMCwgMTk5OSkgKyB0aGVtZV9idygpICsgdGhlbWUobGVnZW5kLnBvc2l0aW9uID0gImJvdHRvbSIpICsgIAogIGxhYnModGl0bGUgPSAiRmlndXJlIDJhOiBUaW1lIGV2b2x1dGlvbiBvZiBIMSAtPiBIMSIsIHggPSAidGltZSIsIHkgPSAiSDEgLT4gSDEiKSAKCmZpZzJiX2dncGxvdCA8LSBnZ3Bsb3QoSDJQMl9lcnJvcl9IMXRvSDFfZ2dwbG90LCBhZXModHlwZSwgYWJzKEludFMpKSkgKwogICAgc2NhbGVfY29sb3VyX21hbnVhbCh2YWx1ZXMgPSBjKCIjZmY0YjAwIiwgIiM0ZGM0ZmYiLCAiI2Y2YWEwMCIpKSArCiAgICBzY2FsZV9zaGFwZV9tYW51YWwodmFsdWVzID0gYygxNSwgMTYsIDE3KSkgKwogICAgZ2VvbV9ib3hwbG90KG91dGxpZXIuc2hhcGUgPSBOQSkgKwogICAgZ2VvbV9qaXR0ZXIoYWVzKHNoYXBlID0gdHlwZSwgY29sb3IgPSB0eXBlLCBhbHBoYSA9IDAuMSksIHdpZHRoID0gMC4yNSwgc2l6ZSA9IDMpICsKICAgIHRoZW1lX2J3KCkgKyB0aGVtZShsZWdlbmQucG9zaXRpb24gPSAiYm90dG9tIikgKyAKICAgIGxhYnMgKHRpdGxlID0gIkZpZ3VyZSAyYjogQ29tcGFyaXNvbiB0byBwYXJhbWV0cmljIElTOiBIMSAtPiBIMSIpIAoKcGxvdChmaWcyYV9nZ3Bsb3QpCmdnc2F2ZSgiZmlnMmEucGRmIiwgd2lkdGggPSA2LCBoZWlnaHQgPSA0KQpwbG90KGZpZzJiX2dncGxvdCkKZ2dzYXZlKCJmaWcyYi5wZGYiLCB3aWR0aCA9IDQsIGhlaWdodCA9IDQpCmBgYAoKIyMjIyMgWzQuNi40XSBDb21wYXJpc29uIGZvciB0aGUgb2ZmLWRpYWdvbmFsIGVsZW1lbnQgKEZpZy4gMmNkOiBQMSAtPiBIMSk6IGdncGxvdAoKYGBge3J9CmZpZzJjX2dncGxvdCA8LSBnZ3Bsb3QoZGF0YSA9IEgyUDJfUDF0b0gxX2dncGxvdCkgKwogIHNjYWxlX2NvbG91cl9tYW51YWwodmFsdWVzID0gYygiI2ZmNGIwMCIsICIjNGRjNGZmIiwgIiNmNmFhMDAiKSkgKwogIHNjYWxlX3NoYXBlX21hbnVhbCh2YWx1ZXMgPSBjKDE1LCAxNiwgMTcpKSArCuOAgGdlb21fbGluZShhZXMoeCA9IHRpbWUsIHkgPSBJbnRTLCBncm91cCA9IHR5cGUsIGNvbG9yID0gdHlwZSkpICsKICBnZW9tX3BvaW50KGFlcyh4ID0gdGltZSwgeSA9IEludFMsIGNvbG9yID0gdHlwZSwgc2hhcGUgPSB0eXBlKSwgc2l6ZSA9IDIpICsKICB4bGltKDE4MDAsIDE5OTkpICsgdGhlbWVfYncoKSArIHRoZW1lKGxlZ2VuZC5wb3NpdGlvbiA9ICJib3R0b20iKSArICAgCiAgbGFicyh0aXRsZSA9ICJGaWd1cmUgMmM6IFRpbWUgZXZvbHV0aW9uIG9mIFAxIC0+IEgxIiwgeCA9ICJ0aW1lIiwgeSA9ICJQMSAtPiBIMSIpIAoKZmlnMmRfZ2dwbG90IDwtIGdncGxvdChIMlAyX2Vycm9yX1AxdG9IMV9nZ3Bsb3QsIGFlcyh0eXBlLCBhYnMoSW50UykpKSArCiAgICBzY2FsZV9jb2xvdXJfbWFudWFsKHZhbHVlcyA9IGMoIiNmZjRiMDAiLCAiIzRkYzRmZiIsICIjZjZhYTAwIikpICsKICAgIHNjYWxlX3NoYXBlX21hbnVhbCh2YWx1ZXMgPSBjKDE1LCAxNiwgMTcpKSArCiAgICBnZW9tX2JveHBsb3Qob3V0bGllci5zaGFwZSA9IE5BKSArCiAgICBnZW9tX2ppdHRlcihhZXMoc2hhcGUgPSB0eXBlLCBjb2xvciA9IHR5cGUsIGFscGhhID0gMC4xKSwgd2lkdGggPSAwLjI1LCBzaXplID0gMykgKwogICAgdGhlbWVfYncoKSArIHRoZW1lKGxlZ2VuZC5wb3NpdGlvbiA9ICJib3R0b20iKSArICAKICAgIGxhYnMgKHRpdGxlID0gIkZpZ3VyZSAyZDogQ29tcGFyaXNvbiB0byBwYXJhbWV0cmljIElTOiBQMSAtPiBIMSIpIAoKcGxvdChmaWcyY19nZ3Bsb3QpCmdnc2F2ZSgiZmlnMmMucGRmIiwgd2lkdGggPSA2LCBoZWlnaHQgPSA0KQpwbG90KGZpZzJkX2dncGxvdCkKZ2dzYXZlKCJmaWcyZC5wZGYiLCB3aWR0aCA9IDQsIGhlaWdodCA9IDQpCgpgYGAKCiMjIyMjIFs0LjYuNV0gQ29tcGFyaXNvbiBmb3IgYm90aCBkaWFnb25hbCBhbmQgb2ZmLWRpYWdvbmFsIGJ5IGNvcnJlbGF0aW9uL3JlZ3Jlc3Npb24KYGBge3J9CiNmb3IgZGlhZ29uYWwgZWxlbWVudCAoSDEgLT4gSDEpCnBsb3QoZEZfSDFkSDEoSFBfcmVzdWx0KVstZmluYWxfSURdLCBIUF9tX3NtYXBfcmVzMl9zJHNtYXBfY29lZmZpY2llbnRzW1sxXV0kY18xWy1maW5hbF9JRF0gLSBkZWx0YV8xMSwgCiAgICAgeGxhYiA9ICJ0aGVvcmV0aWNhbCBjb2VmZmljaWVudCAoSDEgLT4gSDEpIiwKICAgICB5bGFiID0gInN0YW5kYXJkIFMtbWFwIGNvZWZmaWNpZW50IChIMSAtPiBIMSkiLAogICAgICkKYWJsaW5lKGNvZWYgPSBjKDAsMSkpCgpjb3IoZEZfSDFkSDEoSFBfcmVzdWx0KVstZmluYWxfSURdLCBIUF9tX3NtYXBfcmVzMl9zJHNtYXBfY29lZmZpY2llbnRzW1sxXV0kY18xWy1maW5hbF9JRF0gLSBkZWx0YV8xMSkKI1kgc2hvdWxkIGJlIHRoZSB0aGVvcmV0aWNhbCBjb2VmZmljaWVudAp4IDwtIEhQX21fc21hcF9yZXMyX3Mkc21hcF9jb2VmZmljaWVudHNbWzFdXSRjXzFbLWZpbmFsX0lEXSAtIGRlbHRhXzExCnN1bW1hcnkobG0oZEZfSDFkSDEoSFBfcmVzdWx0KVstZmluYWxfSURdIH4geCkpCgpwbG90KGRGX0gxZEgxKEhQX3Jlc3VsdClbLWZpbmFsX0lEXSwgTURSX1NtYXBfZEgxZEgxLAogICAgIHhsYWIgPSAidGhlb3JldGljYWwgY29lZmZpY2llbnQgKEgxIC0+IEgxKSIsCiAgICAgeWxhYiA9ICJNRFIgUy1tYXAgY29lZmZpY2llbnQgKEgxIC0+IEgxKSIKICAgICApCmFibGluZShjb2VmID0gYygwLDEpKQoKY29yKGRGX0gxZEgxKEhQX3Jlc3VsdClbLWZpbmFsX0lEXSwgTURSX1NtYXBfZEgxZEgxKQpzdW1tYXJ5KGxtKGRGX0gxZEgxKEhQX3Jlc3VsdClbLWZpbmFsX0lEXSB+IE1EUl9TbWFwX2RIMWRIMSkpCgojZm9yIG9mZi1kaWFnb25hbCBlbGVtZW50IChQMSAtPiBIMSkKcGxvdChkRl9IMWRQMShIUF9yZXN1bHQpWy1maW5hbF9JRF0gKiBIUF9yZXN1bHQuc2RbM10gLyBIUF9yZXN1bHQuc2RbMV0sIEhQX21fc21hcF9yZXMyX3Mkc21hcF9jb2VmZmljaWVudHNbWzFdXSRjXzNbLWZpbmFsX0lEXSwKICAgICB4bGFiID0gInRoZW9yZXRpY2FsY29lZmZpY2llbnQgKFAxIC0+IEgxKSIsCiAgICAgeWxhYiA9ICJzdGFuZGFyZCBTLW1hcCBjb2VmZmljaWVudCAoUDEgLT4gSDEpIgogICAgICkKYWJsaW5lKGNvZWYgPSBjKDAsMSkpCgpjb3IoZEZfSDFkUDEoSFBfcmVzdWx0KVstZmluYWxfSURdICogSFBfcmVzdWx0LnNkWzNdIC8gSFBfcmVzdWx0LnNkWzFdLCBIUF9tX3NtYXBfcmVzMl9zJHNtYXBfY29lZmZpY2llbnRzW1sxXV0kY18zWy1maW5hbF9JRF0pCnkgPC0gZEZfSDFkUDEoSFBfcmVzdWx0KVstZmluYWxfSURdICogSFBfcmVzdWx0LnNkWzNdIC8gSFBfcmVzdWx0LnNkWzFdCnN1bW1hcnkobG0oeSB+IEhQX21fc21hcF9yZXMyX3Mkc21hcF9jb2VmZmljaWVudHNbWzFdXSRjXzNbLWZpbmFsX0lEXSkpCgpwbG90KGRGX0gxZFAxKEhQX3Jlc3VsdClbLWZpbmFsX0lEXSAqIEhQX3Jlc3VsdC5zZFszXSAvIEhQX3Jlc3VsdC5zZFsxXSwgTURSX1NtYXBfZEgxZFAxLAogICAgIHhsYWIgPSAidGhlb3JldGljYWxjb2VmZmljaWVudCAoUDEgLT4gSDEpIiwKICAgICB5bGFiID0gIk1EUiBTLW1hcCBjb2VmZmljaWVudCAoUDEgLT4gSDEpIgogICAgICkKYWJsaW5lKGNvZWYgPSBjKDAsMSkpCgpjb3IoTURSX1NtYXBfZEgxZFAxLCBkRl9IMWRQMShIUF9yZXN1bHQpWy1maW5hbF9JRF0gKiBIUF9yZXN1bHQuc2RbM10gLyBIUF9yZXN1bHQuc2RbMV0pCnN1bW1hcnkobG0oeSB+IE1EUl9TbWFwX2RIMWRQMSkpCiAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAKYGBgCgoKIyMjIFs1XSBNb2RlbDAyIHNldHRpbmcKIyMjIyBbNS4xXSBNb2RlbCBlcXVhdGlvbnMgZm9yIHRoZSA1LXNwZWNpZXMgY291cGxlZCBmb29kIGNoYWluIE9ERSBtb2RlbApcWwpcZnJhY3tkUF9pfXtkdH0gPSB2X2kgXGxhbWJkYV9pIFxmcmFje1BfaSBDX2l9e0NfaSArIENfaV4qfSAtIHZfaSBQX2ksIFxxdWFkIChpPTEsMikgXHRhZ3sxfQpcXQoKXFsKXGZyYWN7ZENfaX17ZHR9ID0gXG11X2kgXGthcHBhX2kgXGZyYWN7Q19pIFJ9e1IgKyBSXip9IC0gdl9pIFxsYW1iZGFfaSBcZnJhY3tQX2kgQ19pfXtDX2kgKyBDX2leKn0gLSBcbXVfaSBDX2ksIFxxdWFkIChpPTEsMikgXHRhZ3syfQpcXQoKXFsKXGZyYWN7ZFJ9e2R0fSA9IFIgXGxlZnQoIDEgLSBcZnJhY3tSfXtrfSBccmlnaHQpIC0gXHN1bV97aT0xLDJ9IFxtdV9pIFxrYXBwYV9pIFxmcmFje0NfaVJ9e1IgKyBSXip9Llx0YWd7M30KXF0KCiMjIyMgWzUuMl0gUGFyYW1ldGVycyBhbmQgc2V0dGluZ3MgZm9yIHRoZSA1LXNwZWNpZXMgY291cGxlZCBmb29kIGNoYWluIE9ERSBtb2RlbAojIyMjIyBbNS4yLjFdIFBhcmFtZXRlciB2YWx1ZSBzZXR0aW5nCmBgYHtyfQp2MSA8LSAwLjEKdjIgPC0gMC4wNwpsYW1iZDEgPC0gMy4yCmxhbWJkMiA8LSAyLjkKQ3N0YXIxIDwtIDAuNQpDc3RhcjIgPC0gMC41Cm15dTEgPC0gMC4xNQpteXUyIDwtIDAuMTUKa3AxIDwtIDIuNQprcDIgPC0gMi4wClJzdGFyIDwtIDAuMwprIDwtIDEuMgpgYGAKIyMjIyMgWzUuMi4yXSBTZXR0aW5ncyBmb3IgbnVtZXJpY2FsbHkgc29sdmluZyBPREVzCmBgYHtyfQpqX1AxIDwtIDEKal9QMiA8LSAyCmpfQzEgPC0gMwpqX0MyIDwtIDQKal9SIDwtIDUKYGBgCiMjIyMjIFs1LjIuM10gRnVuY3Rpb25zIHNwZWNpZmljIHRvIHRoZSA1LXNwIG1vZGVsCmBgYHtyfQpkUDFkdCA8LSBmdW5jdGlvbihpbl92ZWMsIHQpCnsKICBncm93dGggPC0gdjEgKiBsYW1iZDEgKiBpbl92ZWNbal9QMV0gKiBpbl92ZWNbal9DMV0gLyAoaW5fdmVjW2pfQzFdICsgQ3N0YXIxKQogIG1vcnRhbGl0eSA8LSB2MSAqIGluX3ZlY1tqX1AxXQogIHJldHVybihncm93dGggLSBtb3J0YWxpdHkpCn0KCmRQMmR0IDwtIGZ1bmN0aW9uKGluX3ZlYywgdCkKewogIGdyb3d0aCA8LSB2MiAqIGxhbWJkMiAqIGluX3ZlY1tqX1AyXSAqIGluX3ZlY1tqX0MyXSAvIChpbl92ZWNbal9DMl0gKyBDc3RhcjIpCiAgbW9ydGFsaXR5IDwtIHYyICogaW5fdmVjW2pfUDJdCiAgcmV0dXJuKGdyb3d0aCAtIG1vcnRhbGl0eSkKfQoKZEMxZHQgPC0gZnVuY3Rpb24oaW5fdmVjLCB0KQp7CiAgZ3Jvd3RoIDwtIG15dTEgKiBrcDEgKiBpbl92ZWNbal9DMV0gKiBpbl92ZWNbal9SXSAvIChpbl92ZWNbal9SXSArIFJzdGFyKQogIG1vcnRhbGl0eSA8LSB2MSAqIGxhbWJkMSAqIGluX3ZlY1tqX1AxXSAqIGluX3ZlY1tqX0MxXSAvIChpbl92ZWNbal9DMV0gKyBDc3RhcjEpICsgbXl1MSAqIGluX3ZlY1tqX0MxXQogIHJldHVybihncm93dGggLSBtb3J0YWxpdHkpCn0KCmRDMmR0IDwtIGZ1bmN0aW9uKGluX3ZlYywgdCkKewogIGdyb3d0aCA8LSBteXUyICoga3AyICogaW5fdmVjW2pfQzJdICogaW5fdmVjW2pfUl0gLyAoaW5fdmVjW2pfUl0gKyBSc3RhcikKICBtb3J0YWxpdHkgIDwtIHYyICogbGFtYmQyICogaW5fdmVjW2pfUDJdICogaW5fdmVjW2pfQzJdIC8gKGluX3ZlY1tqX0MyXSArIENzdGFyMikgKyBteXUyICogaW5fdmVjW2pfQzJdCiAgcmV0dXJuKGdyb3d0aCAtIG1vcnRhbGl0eSkKfQoKZFJkdCA8LSBmdW5jdGlvbihpbl92ZWMsIHQpCnsKICBncm93dGggPC0gaW5fdmVjW2pfUl0gKiAoMS4wIC0gaW5fdmVjW2pfUl0gLyBrKQogIG1vcnRhbGl0eSA8LSBteXUxICoga3AxICogaW5fdmVjW2pfQzFdICogaW5fdmVjW2pfUl0gLyAoaW5fdmVjW2pfUl0gKyBSc3RhcikgKyBteXUyICoga3AyICogaW5fdmVjW2pfQzJdICogaW5fdmVjW2pfUl0gLyAoaW5fdmVjW2pfUl0gKyBSc3RhcikKICByZXR1cm4oZ3Jvd3RoIC0gbW9ydGFsaXR5KQp9CgojZnVuY3Rpb24gdG8gY2FsY3VsYXRlIGFsbCBjb2VmZmljaWVudHMsIGZpdmUgZGltZW5zaW9uYWwKZGlmZl81c3AgPC0gZnVuY3Rpb24oaW5fdmVjLCByZWZfZGF0YSwgdCwgaF9pbnRlcnZhbCwgZGltKXsKICB0ZW1wX3ZlYyA8LSBudW1lcmljKGRpbSkKICB0ZW1wX3ZlY1tqX1AxXSA8LSBkUDFkdChpbl92ZWMsIHQpCiAgdGVtcF92ZWNbal9QMl0gPC0gZFAyZHQoaW5fdmVjLCB0KQogIHRlbXBfdmVjW2pfQzFdIDwtIGRDMWR0KGluX3ZlYywgdCkKICB0ZW1wX3ZlY1tqX0MyXSA8LSBkQzJkdChpbl92ZWMsIHQpCiAgdGVtcF92ZWNbal9SXSA8LSBkUmR0KGluX3ZlYywgdCkKICB0ZW1wX3ZlYwp9ICAKYGBgCiMjIyMjIFs1LjIuNF0gSW5pdGlhbCBzZXR0aW5nIGFuZCBjb25kaXRpb25zCmBgYHtyfQpkaW1fbW9kZWwxIDwtIDUKbnYwIDwtIG51bWVyaWMoZGltX21vZGVsMSkKbnYgPC0gbnVtZXJpYyhkaW1fbW9kZWwxKQoKbnYwW2pfUl0gPC0gMS4wCm52MFtqX0MxXSA8LSAwLjUKbnYwW2pfQzJdIDwtIDAuOApudjBbal9QMV0gPC0gMC43Cm52MFtqX1AyXSA8LSAwLjgKCmRlbHRhdCA8LSAwLjAxCmBgYAoKIyMjIyBbNS4zXSBTb2x2aW5nIHRoZSBtb2RlbAojIyMjIyBbNS4zLjFdIFNvbHZpbmcgdGhlIG1vZGVsIGJ5IHRoZSBSSzQgbWV0aG9kCmBgYHtyfQp0IDwtIDAuMCAgIyBpbml0aWFsIGNvbmRpdGlvbiAoaW5pdGlhbCB0aW1lLCAwKQplbmRfdGltZSA8LSAyMDAwOyB0YXUgPC0gNTsgdHJhbnNpZW50X3BlcmlvZCA8LSAxMDAwCndyaXRlX2luZGV4IDwtIDEKCiNJbml0aWFsIGNvbmRpdGlvbiBzZXQKbnYgPC0gbnYwIAoKI3dyaXRlIGluaXRpYWwgY29uZGl0aW9uCmNhdCh0LCBudiwgIlxuIikKCiNGb3IgdGhlIHRyYW5zaWVudCBkeW5hbWljcyAoUlVOIEJVUk4pCmZvcihpIGluIDE6YXMuaW50ZWdlcih0cmFuc2llbnRfcGVyaW9kIC8gZGVsdGF0KSl7CiAgbnYgPC0gcms0KGluX3ZlYyA9IG52LCB0aW1lID0gdCwgaF9pbnRlcnZhbCA9IGRlbHRhdCwgZGltID0gZGltX21vZGVsMSwgZGlmZl92ZWMgPSBkaWZmXzVzcCkKICB0IDwtIHQgKyBkZWx0YXQgIyB1cGRhdGUgdGltZQp9CgojIHJlY29yZCB0aGUgaW5pdGlhbCBjb25kaXRpb24gYWZ0ZXIgQlVSTklORyBwaGFzZQpyazRfcmVzdWx0IDwtIGRhdGEuZnJhbWUodCA9IHQsIFAxID0gbnZbal9QMV0sIFAyID0gbnZbal9QMl0sIEMxID0gbnZbal9DMV0sIEMyID0gbnZbal9DMl0sIFIgPSBudltqX1JdKQoKI0FmdGVyIHRyYW5zaWVudCBwZXJpb2QKZm9yKGkgaW4gMTphcy5pbnRlZ2VyKChlbmRfdGltZSAtIHRyYW5zaWVudF9wZXJpb2QpIC8gZGVsdGF0KSl7CiAgbnYgPC0gcms0KGluX3ZlYyA9IG52LCB0aW1lID0gdCwgaF9pbnRlcnZhbCA9IGRlbHRhdCwgZGltID0gZGltX21vZGVsMSwgZGlmZl92ZWMgPSBkaWZmXzVzcCkKICB0IDwtIHQgKyBkZWx0YXQgIyB1cGRhdGUgdGltZQogICMjI3JlY29yZCB0aGUgcmVzdWx0IGV2ZXJ5ICJ0YXUgb25seQogIGlmKHdyaXRlX2luZGV4IDwgYXMuaW50ZWdlcih0YXUgLyBkZWx0YXQpKXsKICAgIHdyaXRlX2luZGV4IDwtIHdyaXRlX2luZGV4ICsgMQogIH0KICBlbHNlIHsKICAgICNjYXQodGltZSwgbnZfZWUxLCJcbiIpCiAgICByazRfcmVzdWx0IDwtIHJiaW5kLmRhdGEuZnJhbWUocms0X3Jlc3VsdCwgYyh0LCBudltqX1AxXSwgbnZbal9QMl0sIG52W2pfQzFdLCBudltqX0MyXSwgbnZbal9SXSkpCiAgICB3cml0ZV9pbmRleCA8LSAxCiAgfQp9CmhlYWQocms0X3Jlc3VsdCkKCnNhdmVSRFMocms0X3Jlc3VsdCwgInJrNF9yZXN1bHRfNXNwX21vZGVsLm9iaiIpCmBgYAoKIyMjIyMgWzUuMy4yXSBCYXNpYyBwbG90IGZvciB0aGUgcmVzdWx0CmBgYHtyfQpwbG90KHJrNF9yZXN1bHQkdCwgcms0X3Jlc3VsdCRDMSwgY29sID0gInJlZCIsIHR5cGUgPSAibCIsIHhsYWIgPSAidGltZSIsIHlsYWIgPSAiYWJ1bmRhbmNlIiwgeWxpbSA9IGMoMCwgMi4wKSkKcGFyKG5ldyA9IFQpCnBsb3Qocms0X3Jlc3VsdCR0LCByazRfcmVzdWx0JEMyLCBjb2wgPSAiYmx1ZSIsIHR5cGUgPSAibCIsIHhsYWIgPSAiIiwgeWxhYiA9ICIiLCB5bGltID0gYygwLCAyLjApKQpwYXIobmV3ID0gVCkKcGxvdChyazRfcmVzdWx0JHQsIHJrNF9yZXN1bHQkUiwgY29sID0gImdyZWVuIiwgdHlwZSA9ICJsIiwgeGxhYiA9ICIiLCB5bGFiID0gIiIsIHlsaW0gPSBjKDAsIDIuMCkpCmBgYAojIyMgWzZdIFRoZW9yZXRpY2FsIGNvZWZmaWNpZW50cyBldmFsdWF0ZWQgYnkgaW5zdGFudGFuZW91cyBKYWNvYmlhbgpUaGUgcGFydGlhbCBkZXJpdmF0aXZlIG9mIGRDMS9kdCAKCgp3aXRoIHJlc3BlY3QgdG8gQzE6ClxbClxmcmFje1xwYXJ0aWFsfXtccGFydGlhbCBDX3sxfX0gXGxlZnQoIFxtdV97MX0gS197MX0gXGZyYWN7Q197MX0gUn17UiArIFJeeyp9fSAtIHZfezF9IFxsYW1iZGFfezF9IFxmcmFje1BfezF9IENfezF9fXtDX3sxfSArIENfezF9XnsqfX0gLSBcbXVfezF9IENfezF9IFxyaWdodCkgPSBLX3sxfSBcbXVfezF9IFxmcmFje1J9e1IgKyBSXnsqfX0gLSB2X3sxfSBcbGFtYmRhX3sxfSBcZnJhY3tQX3sxfSBDX3sxfSp9eyhDX3sxfSArIENfezF9XnsqfSleMn0gLSBcbXVfezF9ClxdCgp3aXRoIHJlc3BlY3QgdG8gUjoKXFsKXGZyYWN7XHBhcnRpYWx9e1xwYXJ0aWFsIFJ9IFxsZWZ0KCBcbXVfezF9IFxrYXBwYV97MX0gXGZyYWN7Q197MX0gUn17UiArIFJeeyp9fSBccmlnaHQpID0gXGthcHBhX3sxfSBcbXVfezF9IFxmcmFje0NfezF9IFJeKn17KFIgKyBSXnsqfSleMn0KXF0KCgpGdW5jdGlvbiBkZWZpbml0aW9uCmBgYHtyfQpkQzFkQzEgPC0gZnVuY3Rpb24oZGF0YSkgewogIGNvZWZmIDwtIG15dTEgKiBrcDEgKiBkYXRhJFIgLyAoZGF0YSRSICsgUnN0YXIpIC0gdjEgKiBsYW1iZDEgKiBkYXRhJFAxICogQ3N0YXIxLyAoZGF0YSRDMSArIENzdGFyMSleMiAtIG15dTEKICByZXR1cm4oY29lZmYpCn0KZEMxZFIgPC0gZnVuY3Rpb24oZGF0YSkgewogIGNvZWZmIDwtIG15dTEgKiBrcDEgKiBkYXRhJEMxICpSc3RhciAvIChkYXRhJFIgKyBSc3RhcileMgogIHJldHVybihjb2VmZikKfQpgYGAKCgojIyMgWzddIEFkanVzdGVkIGludGVyYWN0aW9uIHN0cmVuZ3RocyB3aXRoIG11bHRpdmFyaWF0ZSBTLW1hcApCYXNlZCBvbiBodHRwczovL3VzaGlvLWVjb2xvZ3ktYmxvZy5ibG9nc3BvdC5jb20vMjAxOS8xMi8yMDE5MTIyNWJsb2dnZXIwMDA3Lmh0bWwKCiMjIyMgWzcuMV0gQW5hbHlzaXMgd2l0aCBzdGFuZGFyZGl6YXRpb24KIyMjIyMgWzcuMS4xXSBTdGFuZGFyZGl6YXRpb24KYGBge3J9CnJrNF9yZXN1bHQubWVhbiA8LSBhcHBseShyazRfcmVzdWx0WywgLTFdLCAyLCBtZWFuLCBuYS5ybSA9IFQpICAjIG1lYW4gYWJ1bmRhbmNlCnJrNF9yZXN1bHQuc2QgPC0gYXBwbHkocms0X3Jlc3VsdFssIC0xXSwgMiwgc2QsIG5hLnJtID0gVCkgICAgICAjIFNEIG9mIGFidW5kYW5jZSAKCm1lYW5fbWF0IDwtIG1hdHJpeChyazRfcmVzdWx0Lm1lYW4sIG5yb3cgPSBucm93KHJrNF9yZXN1bHQpICwgbmNvbCA9IGxlbmd0aChyazRfcmVzdWx0Lm1lYW4pLCBieXJvdyA9IFRSVUUpCnNkX21hdCA8LSBtYXRyaXgocms0X3Jlc3VsdC5zZCwgbnJvdyA9IG5yb3cocms0X3Jlc3VsdCkgLCBuY29sID0gbGVuZ3RoKHJrNF9yZXN1bHQubWVhbiksIGJ5cm93ID0gVFJVRSkKCnJrNF9yZXN1bHRfcyA8LSAocms0X3Jlc3VsdFssIC0xXSAtIG1lYW5fbWF0KSAvc2RfbWF0ICMgU3RhbmRhcmRpemVkIGRhdGFzZXQKaGVhZChyazRfcmVzdWx0X3MpCmBgYAoKIyMjIyMgWzcuMS4yXSBBbmFsYXlzaXMgd2l0aCB0aGUgc3RhbmRhcmRpemVkIHRpbWUgc2VyaWVzIGRhdGEgCmBgYHtyfQojIGRhdGEgYmxvY2sgZm9yIHNtYXAKcms0X3NtYXBfYmxvY2tfcyA8LSBkYXRhLmZyYW1lKFAxID0gcms0X3Jlc3VsdF9zJFAxLCBQMiA9IHJrNF9yZXN1bHRfcyRQMiwgQzEgPSByazRfcmVzdWx0X3MkQzEsIEMyID0gcms0X3Jlc3VsdF9zJEMyLCBSID0gcms0X3Jlc3VsdF9zJFIpCgojIGRlbGV0ZSBhIGZldyBjb2x1bW4KI3JrNF9zbWFwX2Jsb2NrX3MgPC0gcms0X3NtYXBfYmxvY2tfc1ssIC1qX1AyXSAjZGVsZXRlIFAyIGZyb20gdGhlIGVtYmVkZGluZwoKIyBjb25kdWN0aW5nIHNtYXAgZm9yIG9idGFpbmluZyB0aGUgb3B0aW1hbCB0aGV0YQpyazRfbV9zbWFwX3Jlc19zIDwtIGJsb2NrX2xubHAocms0X3NtYXBfYmxvY2tfcywgbWV0aG9kID0gInMtbWFwIiwKICAgICAgICAgICAgICAgICAgICAgICAgIHRhcmdldF9jb2x1bW4gPSBqX0MxLCAKICAgICAgICAgICAgICAgICAgICAgICAgIHRoZXRhID0gYygwLCAxZS0wNCwgM2UtMDQsIDAuMDAxLCAwLjAwMywgMC4wMSwgMC4wMywgMC4xLCAwLjMsIDAuNSwgMC43NSwgMSwgMS41LCAyLCAzLCA0LCA2LCA4KSwKICAgICAgICAgICAgICAgICAgICAgICAgIHNpbGVudCA9IFRSVUUpCmBgYApQbG90dGluZyB0aGUgZWZmZWN0IG9mIHRoZXRhCmBgYHtyfQpwbG90KHJrNF9tX3NtYXBfcmVzX3MkdGhldGEsIHJrNF9tX3NtYXBfcmVzX3Mkcm1zZSwgdHlwZSA9ICJiIikKKHJrNF9vcHRfdGhldGFfcyA8LSByazRfbV9zbWFwX3Jlc19zJHRoZXRhW3doaWNoLm1pbihyazRfbV9zbWFwX3Jlc19zJHJtc2UpXSkKYGBgCkNvbmR1Y3Rpbmcgc3RhbmRhcmQgc21hcCB3aXRoIHRoZSBvcHRpbWFsIHRoZXRhCmBgYHtyfQpyazRfbV9zbWFwX3JlczJfcyA8LSBibG9ja19sbmxwKHJrNF9zbWFwX2Jsb2NrX3MsIG1ldGhvZCA9ICJzLW1hcCIsIAogICAgICAgICAgICAgICAgICAgICAgICAgICAgICB0YXJnZXRfY29sdW1uID0gal9DMSwgCiAgICAgICAgICAgICAgICAgICAgICAgICAgICAgIHRoZXRhID0gcms0X29wdF90aGV0YV9zLCAKICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgc2lsZW50ID0gVFJVRSwgCiAgICAgICAgICAgICAgICAgICAgICAgICAgICAgIHNhdmVfc21hcF9jb2VmZmljaWVudHMgPSBUUlVFKQpoZWFkKGFzLmRhdGEuZnJhbWUocms0X21fc21hcF9yZXMyX3Mkc21hcF9jb2VmZmljaWVudHNbWzFdXSkpCmBgYAoKCiMjIyMgWzcuMl0gQ29tcGFyZSBzdGFuZGFyZCBTLW1hcCBhbmQgaW5zdGFudGFuZW91cyBpbnRlcmFjdGlvbiBzdHJlbmd0aHMgKElJUykKYGBge3J9CmZpbmFsX0lEIDwtIDIwMQpwbG90KHJrNF9yZXN1bHQkdFstZmluYWxfSURdLCByazRfbV9zbWFwX3JlczJfcyRzbWFwX2NvZWZmaWNpZW50c1tbMV1dJGNfM1stZmluYWxfSURdIC0gMS4wLCB0eXBlID0gImwiLCBjb2wgPSAxLCB5bGltID0gYygtMSwgMSksIHhsYWIgPSAidGltZSIsIHlsYWIgPSAiU21hcCBjb2VmZmljaWVudDogQzEgLT4gQzEiKQpwYXIobmV3ID0gVCkKcGxvdChyazRfcmVzdWx0JHRbLWZpbmFsX0lEXSwgdGF1KmRDMWRDMShyazRfcmVzdWx0KVstZmluYWxfSURdLCB0eXBlID0gImwiLCBjb2wgPSAiYmx1ZSIsIHlsaW0gPSBjKC0xLCAxKSwgeGxhYiA9ICIiLCB5bGFiID0gIiIpCmBgYAojIyMgWzhdIERlcml2aW5nIG1hdGhlbWF0aWNhbGx5IGNvcnJlY3QgaW50ZXJhY3Rpb24gY29lZmZpY2llbnRzCiMjIyMgWzguMV0gTW9kZWwgc2V0dGluZwojIyMjIyBbOC4xLjFdIExpc3Qgb2YgcGFydGlhbCBkZXJpdmF0aXZlcyAoSmFjb2JpYW4pClxbClxmcmFje1xwYXJ0aWFsIEZfe1BfMX19e1xwYXJ0aWFsIFBfMX0gPSB2XzEgXGxhbWJkYV8xIFxmcmFje0NfMX17Q18xICsgQ18xXip9IC0gdl8xLApcZnJhY3tccGFydGlhbCBGX3tQXzF9fXtccGFydGlhbCBQXzJ9ID0gMCwgClxmcmFje1xwYXJ0aWFsIEZfe1BfMX19e1xwYXJ0aWFsIENfMX0gPSB2XzEgXGxhbWJkYV8xIFxmcmFje1BfMSBDXzFeKn17KENfMSArIENfMV4qKV4yfSwKXGZyYWN7XHBhcnRpYWwgRl97UF8xfX17XHBhcnRpYWwgQ18yfSA9IFxmcmFje1xwYXJ0aWFsIEZfe1BfMX19e1xwYXJ0aWFsIFJ9ID0gMCwgIApcXQoKXFsKXGZyYWN7XHBhcnRpYWwgRl97UF8yfX17XHBhcnRpYWwgUF8xfSA9IDAsIApcZnJhY3tccGFydGlhbCBGX3tQXzJ9fXtccGFydGlhbCBQXzJ9ID0gdl8yIFxsYW1iZGFfMiBcZnJhY3tDXzJ9e0NfMiArIENfMl4qfSAtIHZfMiwgClxmcmFje1xwYXJ0aWFsIEZfe1BfMn19e1xwYXJ0aWFsIENfMX0gPSAwLCAKXGZyYWN7XHBhcnRpYWwgRl97UF8yfX17XHBhcnRpYWwgQ18yfSA9IHZfMiBcbGFtYmRhXzIgXGZyYWN7UF8yIENfMl4qfXsoQ18yICsgQ18yXiopXjJ9LCAKXGZyYWN7XHBhcnRpYWwgRl97UF8yfX17XHBhcnRpYWwgUn0gPSAwLCAgClxdCgpcWwpcZnJhY3tccGFydGlhbCBGX3tDXzF9fXtccGFydGlhbCBQXzF9ID0gLXZfMSBcbGFtYmRhXzEgXGZyYWN7Q18xfXtDXzEgKyBDXzFeKn0sClxmcmFje1xwYXJ0aWFsIEZfe0NfMX19e1xwYXJ0aWFsIFBfMn0gPSAwLCAKXGZyYWN7XHBhcnRpYWwgRl97Q18xfX17XHBhcnRpYWwgQ18xfSA9IFxtdV8xIFxrYXBwYV8xIFxmcmFje1J9e1IgKyBSXip9IC0gdl8xIFxsYW1iZGFfMSBcZnJhY3tQXzEgQ18xXip9eyhDXzEgKyBDXzFeKileMn0gLSBcbXVfMSwgClxmcmFje1xwYXJ0aWFsIEZfe0NfMX19e1xwYXJ0aWFsIENfMn0gPSAwLApcZnJhY3tccGFydGlhbCBGX3tDXzF9fXtccGFydGlhbCBSfSA9IFxtdV8xIFxrYXBwYV8xIFxmcmFje0NfMSBSXip9eyhSICsgUl4qKV4yfSwgIApcXQoKXFsKXGZyYWN7XHBhcnRpYWwgRl97Q18yfX17XHBhcnRpYWwgUF8xfSA9IDAsIApcZnJhY3tccGFydGlhbCBGX3tDXzJ9fXtccGFydGlhbCBQXzJ9ID0gLXZfMiBcbGFtYmRhXzIgXGZyYWN7Q18yfXtDXzIgKyBDXzJeKn0sClxmcmFje1xwYXJ0aWFsIEZfe0NfMn19e1xwYXJ0aWFsIENfMX0gPSAwLApcZnJhY3tccGFydGlhbCBGX3tDXzJ9fXtccGFydGlhbCBDXzJ9ID0gXG11XzIgXGthcHBhXzIgXGZyYWN7Un17UiArIFJeKn0gLSB2XzIgXGxhbWJkYV8yIFxmcmFje1BfMiBDXzJeKn17KENfMiArIENfMl4qKV4yfSAtIFxtdV8yLCAKXGZyYWN7XHBhcnRpYWwgRl97Q18yfX17XHBhcnRpYWwgUn0gPSBcbXVfMiBca2FwcGFfMiBcZnJhY3tDXzIgUl4qfXsoUiArIFJeKileMn0sICAKXF0KClxbClxmcmFje1xwYXJ0aWFsIEZfe1J9fXtccGFydGlhbCBQXzF9ID0gXGZyYWN7XHBhcnRpYWwgRl97Un19e1xwYXJ0aWFsIFBfMn0gPSAwLCAKXGZyYWN7XHBhcnRpYWwgRl97Un19e1xwYXJ0aWFsIENfMX0gPSAtIFxtdV8xIFxrYXBwYV8xIFxmcmFje1J9e1IgKyBSXip9LApcZnJhY3tccGFydGlhbCBGX3tSfX17XHBhcnRpYWwgQ18yfSA9IC0gXG11XzIgXGthcHBhXzIgXGZyYWN7Un17UiArIFJeKn0sClxmcmFje1xwYXJ0aWFsIEZfe1J9fXtccGFydGlhbCBSfSA9IFxsZWZ0KCAxIC0gXGZyYWN7MiBSfXtrfSBccmlnaHQpLSBcc3VtX3tpPTEsMn0gXG11X2kgXGthcHBhX2kgXGZyYWN7Q19pIFJeKn17KFIgKyBSXiopXjJ9LgpcXQoKIyMjIyMgWzguMS4yXSBGdW5jdGlvbnMgc3BlY2lmaWMgdG8gdGhlIGxpbmVhcml6ZWQgbW9kZWwKUGFydGlhbCBkZXJpdmF0aXZlcwpgYGB7cn0KckZfUDFyWCA8LSBmdW5jdGlvbihpbl92ZWMsIHQpIHsKICBudl9wIDwtIG51bWVyaWMobGVuZ3RoKGluX3ZlYykpCiAgCiAgbnZfcFtqX1AxXSA8LSB2MSAqIGxhbWJkMSAqIGluX3ZlY1tqX0MxXSAvIChpbl92ZWNbal9DMV0gKyBDc3RhcjEpIC0gdjEKICBudl9wW2pfUDJdIDwtIDAKICBudl9wW2pfQzFdIDwtIHYxICogbGFtYmQxICogaW5fdmVjW2pfUDFdICogQ3N0YXIxIC8gKGluX3ZlY1tqX0MxXSArIENzdGFyMSleMgogIG52X3Bbal9DMl0gPC0gMAogIG52X3Bbal9SXSA8LSAwCiAgCiAgcmV0dXJuKG52X3ApCn0KCnJGX1AyclggPC0gZnVuY3Rpb24oaW5fdmVjLCB0KSB7CiAgbnZfcCA8LSBudW1lcmljKGxlbmd0aChpbl92ZWMpKQogIAogIG52X3Bbal9QMl0gPC0gdjIgKiBsYW1iZDIgKiBpbl92ZWNbal9DMl0gLyAoaW5fdmVjW2pfQzJdICsgQ3N0YXIyKSAtIHYyCiAgbnZfcFtqX1AxXSA8LSAwCiAgbnZfcFtqX0MyXSA8LSB2MiAqIGxhbWJkMiAqIGluX3ZlY1tqX1AyXSAqIENzdGFyMiAvIChpbl92ZWNbal9DMl0gKyBDc3RhcjIpXjIKICBudl9wW2pfQzFdIDwtIDAKICBudl9wW2pfUl0gPC0gMAogIAogIHJldHVybihudl9wKQp9CgpyRl9DMXJYIDwtIGZ1bmN0aW9uKGluX3ZlYywgdCkgewogIG52X3AgPC0gbnVtZXJpYyhsZW5ndGgoaW5fdmVjKSkKICAKICBudl9wW2pfUDFdIDwtIC12MSAqIGxhbWJkMSAqIGluX3ZlY1tqX0MxXSAvIChpbl92ZWNbal9DMV0gKyBDc3RhcjEpCiAgbnZfcFtqX1AyXSA8LSAwCiAgbnZfcFtqX0MxXSA8LSBteXUxICoga3AxICogaW5fdmVjW2pfUl0gLyAoaW5fdmVjW2pfUl0gKyBSc3RhcikgLSB2MSAqIGxhbWJkMSAqIGluX3ZlY1tqX1AxXSAqIENzdGFyMS8gKGluX3ZlY1tqX0MxXSArIENzdGFyMSleMiAtIG15dTEKICBudl9wW2pfQzJdIDwtIDAKICBudl9wW2pfUl0gPC0gbXl1MSAqIGtwMSAqIGluX3ZlY1tqX0MxXSAqIFJzdGFyIC8gKGluX3ZlY1tqX1JdICsgUnN0YXIpXjIKICAKICByZXR1cm4obnZfcCkKfQoKckZfQzJyWCA8LSBmdW5jdGlvbihpbl92ZWMsIHQpIHsKICBudl9wIDwtIG51bWVyaWMobGVuZ3RoKGluX3ZlYykpCiAgCiAgbnZfcFtqX1AyXSA8LSAtdjIgKiBsYW1iZDIgKiBpbl92ZWNbal9DMl0gLyAoaW5fdmVjW2pfQzJdICsgQ3N0YXIyKQogIG52X3Bbal9QMV0gPC0gMAogIG52X3Bbal9DMl0gPC0gbXl1MiAqIGtwMiAqIGluX3ZlY1tqX1JdIC8gKGluX3ZlY1tqX1JdICsgUnN0YXIpIC0gdjIgKiBsYW1iZDIgKiBpbl92ZWNbal9QMl0gKiBDc3RhcjIvIChpbl92ZWNbal9DMl0gKyBDc3RhcjIpXjIgLSBteXUyCiAgbnZfcFtqX0MxXSA8LSAwCiAgbnZfcFtqX1JdIDwtIG15dTIgKiBrcDIgKiBpbl92ZWNbal9DMl0gKiBSc3RhciAvIChpbl92ZWNbal9SXSArIFJzdGFyKV4yCiAgCiAgcmV0dXJuKG52X3ApCn0KCnJGX1JyWCA8LSBmdW5jdGlvbihpbl92ZWMsIHQpIHsKICBudl9wIDwtIG51bWVyaWMobGVuZ3RoKGluX3ZlYykpCiAgCiAgbnZfcFtqX1AxXSA8LSAwCiAgbnZfcFtqX1AxXSA8LSAwCiAgbnZfcFtqX0MxXSA8LSAtbXl1MSAqIGtwMSAqIGluX3ZlY1tqX1JdIC8gKGluX3ZlY1tqX1JdICsgUnN0YXIpCiAgbnZfcFtqX0MyXSA8LSAtbXl1MiAqIGtwMiAqIGluX3ZlY1tqX1JdIC8gKGluX3ZlY1tqX1JdICsgUnN0YXIpCiAgbnZfcFtqX1JdIDwtICgxIC0gMiAqIGluX3ZlY1tqX1JdIC8gaykgLSAobXl1MSAqIGtwMSAqIGluX3ZlY1tqX0MxXSArIG15dTIgKiBrcDIgKiBpbl92ZWNbal9DMl0pICogUnN0YXIgLyAoaW5fdmVjW2pfUl0gKyBSc3RhcileMgogIAogIHJldHVybihudl9wKQp9CmBgYApMaW5lYXJsaXplZCBwZXJ0dXJiZWQgT0RFIHN5c3RlbSBlcXVhdGlvbnMKXFsKXGZyYWN7ZFxib2xkc3ltYm9se1xkZWx0YX0odCl9e2R0fSA9IFxtYXRoYmZ7Sn1fe3R9IFxib2xkc3ltYm9se1xkZWx0YX0odCksIFxxdWFkIFxib2xkc3ltYm9se1xkZWx0YX0oMCkgPSBcRGVsdGEgXGJvbGRzeW1ib2x7eH1fe2p9LiBcdGFnezdhfQpcXQoKClxiZWdpbnthbGlnbn0KSUNfe2ksaixhZGp9KGs9a18xKSAmPSAgXGxpbV97XERlbHRhIHggXHRvIDB9IFxmcmFje1xsZWZ0W1xwaGkoXGJvbGRzeW1ib2x7eH0oa18xKSArIFxEZWx0YSB4X2osIFx0YXUpIC0gXHBoaShcYm9sZHN5bWJvbHt4fShrXzEpLCBcdGF1KVxyaWdodF1faX17XERlbHRhIHh9IC0gXGRlbHRhX3tpan1cXAomPSBcbGltX3tcRGVsdGEgeCBcdG8gMH0gXGZyYWN7XGxlZnRbXGJvbGRzeW1ib2x7XGRlbHRhfV9uIChcdGF1KVxyaWdodF1faX17XERlbHRhIHh9IC0gXGRlbHRhX3tpan0gXFwKJlxhcHByb3ggXGZyYWN7XGxlZnRbXGJvbGRzeW1ib2x7XGRlbHRhfV9uIChcdGF1KVxyaWdodF1faX17XERlbHRhIHh9IC0gXGRlbHRhX3tpan0gXHRhZ3s3Y30KXGVuZHthbGlnbn0KCkxpbmVhcmxpemVkIE9ERSBzeXN0ZW0KYGBge3J9CmRQMUxkdCA8LSBmdW5jdGlvbihpbl92ZWMsIHJlZl9kYXRhLCB0KQp7CiAgcmVmX3ZlYyA8LSBhcy5udW1lcmljKHJlZl9kYXRhW3QsIC0xXSkKICByZXR1cm4oYXMubnVtZXJpYyhyRl9QMXJYKHJlZl92ZWMpICUqJSBpbl92ZWMpKQp9CgpkUDJMZHQgPC0gZnVuY3Rpb24oaW5fdmVjLCByZWZfZGF0YSwgdCkKewogIHJlZl92ZWMgPC0gYXMubnVtZXJpYyhyZWZfZGF0YVt0LCAtMV0pCiAgcmV0dXJuKGFzLm51bWVyaWMockZfUDJyWChyZWZfdmVjKSAlKiUgaW5fdmVjKSkKfQoKZEMxTGR0IDwtIGZ1bmN0aW9uKGluX3ZlYywgcmVmX2RhdGEsIHQpCnsKICByZWZfdmVjIDwtIGFzLm51bWVyaWMocmVmX2RhdGFbdCwgLTFdKQogIHJldHVybihhcy5udW1lcmljKHJGX0MxclgocmVmX3ZlYykgJSolIGluX3ZlYykpCn0KCmRDMkxkdCA8LSBmdW5jdGlvbihpbl92ZWMsIHJlZl9kYXRhLCB0KQp7CiAgcmVmX3ZlYyA8LSBhcy5udW1lcmljKHJlZl9kYXRhW3QsIC0xXSkKICByZXR1cm4oYXMubnVtZXJpYyhyRl9DMnJYKHJlZl92ZWMpICUqJSBpbl92ZWMpKQp9CgpkUkxkdCA8LSBmdW5jdGlvbihpbl92ZWMsIHJlZl9kYXRhLCB0KQp7CiAgcmVmX3ZlYyA8LSBhcy5udW1lcmljKHJlZl9kYXRhW3QsIC0xXSkKICByZXR1cm4oYXMubnVtZXJpYyhyRl9SclgocmVmX3ZlYykgJSolIGluX3ZlYykpCn0KCgojZnVuY3Rpb24gdG8gY2FsY3VsYXRlIGFsbCBjb2VmZmljaWVudHMsIGZpdmUgZGltZW5zaW9uYWwKZGlmZl9MXzVzcCA8LSBmdW5jdGlvbihpbl92ZWMsIHJlZl9kYXRhLCB0LCBoX2ludGVydmFsLCBkaW0pewogIHRlbXBfdmVjIDwtIG51bWVyaWMoZGltKQogIAogIHRfaW5kZXggPC0gYXMuaW50ZWdlcigodCAvIGhfaW50ZXJ2YWwpICogMikgI3RvIGNvbnZlcnQgY29udGludW91cyB0aW1lIHRvIHRoZSBudW1iZXIgb2Ygcm93CiAgCiAgdGVtcF92ZWNbal9QMV0gPC0gZFAxTGR0KGluX3ZlYywgcmVmX2RhdGEsIHRfaW5kZXgpCiAgdGVtcF92ZWNbal9QMl0gPC0gZFAyTGR0KGluX3ZlYywgcmVmX2RhdGEsIHRfaW5kZXgpCiAgdGVtcF92ZWNbal9DMV0gPC0gZEMxTGR0KGluX3ZlYywgcmVmX2RhdGEsIHRfaW5kZXgpCiAgdGVtcF92ZWNbal9DMl0gPC0gZEMyTGR0KGluX3ZlYywgcmVmX2RhdGEsIHRfaW5kZXgpCiAgdGVtcF92ZWNbal9SXSA8LSBkUkxkdChpbl92ZWMsIHJlZl9kYXRhLCB0X2luZGV4KQogIHRlbXBfdmVjCn0gIApgYGAKIyMjIyBbOC4yXSBTb2x2aW5nIHRoZSBtb2RlbAojIyMjIyBbOC4yLjFdIFByZXBhcmluZyB0aGUgZmluZSBzb2x1dGlvbiBvZiB0aGUgT0RFcyB3aXRob3V0IHBlcnR1cmJhdGlvbgpTaW5jZSByazQoKSBpbmNsdWRlcyB0aGUgZXZhbHVhdGlvbiBvZiBkZXJpdmF0aXZlcyBhdCB0ICsgZGVsdGF0LzIsIHdlIG5lZWQgdG8gaGF2ZSBudW1lcmljYWwgc29sdXRpb25zIHdpdGggdGhlIGhpZ2ggcmVzb2x1dGlvbiB3aXRoIGRlbHRhdC8yCmBgYHtyfQp0IDwtIDAuMCAgIyBpbml0aWFsIGNvbmRpdGlvbiAoaW5pdGlhbCB0aW1lLCAwKQplbmRfdGltZSA8LSAyMDAwOyB0YXUgPC0gNTsgdHJhbnNpZW50X3BlcmlvZCA8LSAxMDAwCndyaXRlX2luZGV4IDwtIDEKZGVsdGF0X2ZpbmUgPC0gZGVsdGF0ICogMC41CgojSW5pdGlhbCBjb25kaXRpb24gc2V0Cm52X3JrNF9maW5lIDwtIG52MCAKCiMgd3JpdGUgaW5pdGlhbCBjb25kaXRpb24KY2F0KHQsIG52X3JrNF9maW5lLCAiXG4iKQoKI0ZvciB0aGUgdHJhbnNpZW50IGR5bmFtaWNzIChSVU4gQlVSTikKZm9yKGkgaW4gMTphcy5pbnRlZ2VyKHRyYW5zaWVudF9wZXJpb2QgLyBkZWx0YXRfZmluZSkpewogIG52X3JrNF9maW5lIDwtIHJrNChpbl92ZWMgPSBudl9yazRfZmluZSwgdGltZSA9IHQsIGhfaW50ZXJ2YWwgPSBkZWx0YXRfZmluZSwgZGltID0gZGltX21vZGVsMSwgZGlmZl92ZWMgPSBkaWZmXzVzcCkKICB0IDwtIHQgKyBkZWx0YXRfZmluZSAjIHVwZGF0ZSB0aW1lCn0KCiMgcmVjb3JkIHRoZSBpbml0aWFsIGNvbmRpdGlvbiBhZnRlciBCVVJOSU5HIHBlcmlvZApyazRfcmVzdWx0X2ZpbmUgPC0gZGF0YS5mcmFtZSh0ID0gdCwgUDEgPSBudl9yazRfZmluZVtqX1AxXSwgUDIgPSBudl9yazRfZmluZVtqX1AyXSwgQzEgPSBudl9yazRfZmluZVtqX0MxXSwgQzIgPSBudl9yazRfZmluZVtqX0MyXSwgUiA9IG52X3JrNF9maW5lW2pfUl0pCgojQWZ0ZXIgdHJhbnNpZW50IHBlcmlvZApmb3IoaSBpbiAxOmFzLmludGVnZXIoKGVuZF90aW1lIC0gdHJhbnNpZW50X3BlcmlvZCkgLyBkZWx0YXRfZmluZSkpewogIG52X3JrNF9maW5lIDwtIHJrNChpbl92ZWMgPSBudl9yazRfZmluZSwgdGltZSA9IHQsIGhfaW50ZXJ2YWwgPSBkZWx0YXRfZmluZSwgZGltID0gZGltX21vZGVsMSwgZGlmZl92ZWMgPSBkaWZmXzVzcCkKICB0IDwtIHQgKyBkZWx0YXRfZmluZSAjIHVwZGF0ZSB0aW1lCiAgcms0X3Jlc3VsdF9maW5lIDwtIHJiaW5kLmRhdGEuZnJhbWUocms0X3Jlc3VsdF9maW5lLCBjKHQsIG52X3JrNF9maW5lW2pfUDFdLCBudl9yazRfZmluZVtqX1AyXSwgbnZfcms0X2ZpbmVbal9DMV0sIG52X3JrNF9maW5lW2pfQzJdLCBudl9yazRfZmluZVtqX1JdKSkKfQoKaGVhZChyazRfcmVzdWx0X2ZpbmUpCiNzYXZlUkRTKHJrNF9yZXN1bHRfZmluZSwgcGFzdGUoImRlZmF1bHQiLCAiX3JrNF9yZXN1bHRfZmluZS5vYmoiLCBzZXA9IiIpKQojc2F2ZVJEUyhyazRfcmVzdWx0X2ZpbmUsIHBhc3RlKFN5cy5EYXRlKCksICJfcms0X3Jlc3VsdF9maW5lLm9iaiIsIHNlcD0iIikpCiAgICAgICAgCmBgYApDb21wYXJpbmcgdGhlIHNvbHV0aW9uIApgYGB7cn0KcGxvdChyazRfcmVzdWx0JHQsIHJrNF9yZXN1bHQkQzEsIGNvbCA9ICJyZWQiLCB0eXBlID0gImwiLCB4bGFiID0gInRpbWUiLCB5bGFiID0gImFidW5kYW5jZSIsIHlsaW0gPSBjKDAsIDIuMCkpCnBhcihuZXcgPSBUKQpwbG90KHJrNF9yZXN1bHRfZmluZSR0LCByazRfcmVzdWx0X2ZpbmUkQzEsIGNvbCA9ICJibGFjayIsIHR5cGUgPSAibCIsIHhsYWIgPSAiIiwgeWxhYiA9ICIiLCB5bGltID0gYygwLCAyLjApLCBsdHkgPSAiZGFzaGVkIikKYGBgCgoKIyMjIyMgWzguMi4yXSBUcmlhbCBmb3IgdGhlIGxpbmVhcml6ZWQgT0RFcyBmb3IgYSBzaG9ydCB0aW1lIHBlcmlvZApgYGB7cn0KI2xvYWRpbmcgdGhlIGRlZmF1bHQKcms0X3Jlc3VsdF9maW5lIDwtIHJlYWRSRFMoImRlZmF1bHRfcms0X3Jlc3VsdF9maW5lLm9iaiIpCgpkZWx0YV94ID0gMC4wMSAjc2l6ZSBvZiBhIHNtYWxsIHBlcnR1cmJhdGlvbgp0IDwtIGRlbHRhdCAvIDIgICMgaW5pdGlhbCBjb25kaXRpb24gKGluaXRpYWwgdGltZSwgdF9hYnMgPSB0cmFuc2llbnRfcGVyaW9kKQp0X2FicyA8LSB0ICsgdHJhbnNpZW50X3BlcmlvZCAtIGRlbHRhdCAvIDIKZW5kX3RpbWUgPC0gMS4wOyB0YXUgPC0gNTsKd3JpdGVfaW5kZXggPC0gMQoKI0luaXRpYWwgY29uZGl0aW9uIApudl9saW5lYXJfcCA8LSBjKDAsIDAsIGRlbHRhX3gsIDAsIDApCiMgcmVjb3JkIHRoZSBpbml0aWFsIGNvbmRpdGlvbgpyZXN1bHRfbGluZWFyX3AgPC0gZGF0YS5mcmFtZSh0ID0gdF9hYnMsIFAxID0gbnZfbGluZWFyX3Bbal9QMV0sIFAyID0gbnZfbGluZWFyX3Bbal9QMl0sIEMxID0gbnZfbGluZWFyX3Bbal9DMV0sIEMyID0gbnZfbGluZWFyX3Bbal9DMl0sIFIgPSBudl9saW5lYXJfcFtqX1JdKQogIApmb3IoaSBpbiAxOmFzLmludGVnZXIoZW5kX3RpbWUgLyBkZWx0YXQpKXsKICBudl9saW5lYXJfcCA8LSByazQoaW5fdmVjID0gbnZfbGluZWFyX3AsIHJlZl9kYXRhID0gcms0X3Jlc3VsdF9maW5lLCB0aW1lID0gdCwgaF9pbnRlcnZhbCA9IGRlbHRhdCwgZGltID0gZGltX21vZGVsMSwgZGlmZl92ZWMgPSBkaWZmX0xfNXNwKQogIHQgPC0gdCArIGRlbHRhdCAjIHVwZGF0ZSB0aW1lIChzdGFydGluZyBmcm9tIHRoZSBtaWRkbGUpCiAgdF9hYnMgPC0gdF9hYnMgKyBkZWx0YXQKICByZXN1bHRfbGluZWFyX3AgPC0gcmJpbmQuZGF0YS5mcmFtZShyZXN1bHRfbGluZWFyX3AsIGModF9hYnMsIG52X2xpbmVhcl9wW2pfUDFdLCBudl9saW5lYXJfcFtqX1AyXSwgbnZfbGluZWFyX3Bbal9DMV0sIG52X2xpbmVhcl9wW2pfQzJdLCBudl9saW5lYXJfcFtqX1JdKSkKfQogcmVzdWx0X2xpbmVhcl9wCgpgYGAKVGhlIGRpcmVjdCBldmFsdWF0aW9uIGJ5IHRoZSBub25saW5lYXIgT0RFCmBgYHtyfQp0IDwtIDEwMDAgLSB0cmFuc2llbnRfcGVyaW9kICsgZGVsdGF0IC8gMiAgIyBpbml0aWFsIGNvbmRpdGlvbiAoaW5pdGlhbCB0aW1lLCB0X2FicyA9IHN0YXJ0X3QpCnRfaW5kZXhfc3RhcnQgPC0gYXMuaW50ZWdlcigodCAvIGRlbHRhdCkgKiAyKQp0X2luZGV4X2VuZCA8LSB0X2luZGV4X3N0YXJ0ICsgYXMuaW50ZWdlcigoMS4wIC8gZGVsdGF0KSAqIDIpCiNJbml0aWFsIGNvbmRpdGlvbiAKbnZfbm9ubGluZWFyX3AgPC0gYXMubnVtZXJpYyhyazRfcmVzdWx0X2ZpbmVbdF9pbmRleF9zdGFydCwgLTFdKSArIGMoMCwgMCwgZGVsdGFfeCwgMCwgMCkKCiMgcmVjb3JkIHRoZSBpbml0aWFsIGNvbmRpdGlvbgpyZXN1bHRfbm9ubGluZWFyX3AgPC0gZGF0YS5mcmFtZSh0ID0gdF9hYnMsIFAxID0gbnZfbm9ubGluZWFyX3Bbal9QMV0sIFAyID0gbnZfbm9ubGluZWFyX3Bbal9QMl0sIEMxID0gbnZfbm9ubGluZWFyX3Bbal9DMV0sIEMyID0gbnZfbm9ubGluZWFyX3Bbal9DMl0sIFIgPSBudl9ub25saW5lYXJfcFtqX1JdKQogIApmb3IoaSBpbiAxOmFzLmludGVnZXIoZW5kX3RpbWUgLyBkZWx0YXQpKXsKICBudl9ub25saW5lYXJfcCA8LSByazQoaW5fdmVjID0gbnZfbm9ubGluZWFyX3AsIHRpbWUgPSB0LCBoX2ludGVydmFsID0gZGVsdGF0LCBkaW0gPSBkaW1fbW9kZWwxLCBkaWZmX3ZlYyA9IGRpZmZfNXNwKQogIHQgPC0gdCArIGRlbHRhdCAjIHVwZGF0ZSB0aW1lIChzdGFydGluZyBmcm9tIHRoZSBtaWRkbGUpCn0KIG52X25vbmxpbmVhcl9wIC0gYXMubnVtZXJpYyhyazRfcmVzdWx0X2ZpbmVbdF9pbmRleF9lbmQsIC0xXSkgI2RpZmZlcmVuY2UgYmV0d2VlbiBwZXJ0dXJiZWQgYW5kIHVucGVydHVyYmVkIHNvbHV0aW9ucwoKYGBgCgojIyMjIyBbOC4yLjNdIEZ1bmN0aW9ucyB0byBjYWxjdWxhdGUgdGhlIGludGVyYWN0aW9uIHN0cmVuZ3RoCmBgYHtyfQojcmVmX2RhdGE6IHRoZSBkYXRhc2V0IHRoYXQgaW5jbHVkZXMgdGhlIGZpbmUgcmVzb2x1dGlvbiBzb2x1dGlvbiBvZiB0aGUgdGFyZ2V0IG5vbmxpbmVhciBPREUgc3lzdGVtcywgb2Ygd2hpY2ggcmVjb3JkIHN0YXJ0ZWQgYXQgYWJzb2x1dGUgdGltZSA9IHRyYW5zaWVudF9wZXJpb2QKI2RlbHRheDogdGhlIHNpemUgb2YgcGVydHVyYmF0aW9uIGF0IHQgPSBoX2ludGVydmFsLzIKI3N0YXJ0X3Q6IHVzdWFsbHkgc3BlY2lmaWVkIGFzIHRyYW5zaWVudF9wZXJpb2QKI3RhdTogdGhlIGludGVydmFsIGZvciB0aGUgY2FsY3VsYXRpb24KI2RpbTogZGltZW5zaW9uIG9mIE9ERSBzeXN0ZW0KI2RpZmZfdmVjOiB0aGUgdmVjdG9yIGZpZWxkIGdlbmVyYXRlZCBieSB0aGUgbGluZWFyaXplZCBPREVzIHdpdGggbm9uLXBlcnR1cmJlZCBzb2x1dGlvbgpwcmVjaXNlX2NvZWZmIDwtIGZ1bmN0aW9uKHJlZl9kYXRhLCBkZWx0YXgsIHN0YXJ0X3QsIHRhdSwgaF9pbnRlcnZhbCwgZGltLCBkaWZmX3ZlYykgewogICNtYXRyaXggdG8gc3RvY2sgcmVzdWx0cwogIG52X2xpbmVhcl9wIDwtIG1hdHJpeCgwLCBucm93ID0gZGltLCBuY29sID0gZGltKQogIAogICNJbml0aWFsIGNvbmRpdGlvbiAKICBudl9saW5lYXJfcFssIGpfUDFdIDwtIGMoZGVsdGF4LCAwLCAwLCAwLCAwKQogIG52X2xpbmVhcl9wWywgal9QMl0gPC0gYygwLCBkZWx0YXgsIDAsIDAsIDApCiAgbnZfbGluZWFyX3BbLCBqX0MxXSA8LSBjKDAsIDAsIGRlbHRheCwgMCwgMCkKICBudl9saW5lYXJfcFssIGpfQzJdIDwtIGMoMCwgMCwgMCwgZGVsdGF4LCAwKQogIG52X2xpbmVhcl9wWywgal9SXSA8LSBjKDAsIDAsIDAsIDAsIGRlbHRheCkKICAKICB0emVybyA8LSBzdGFydF90IC0gdHJhbnNpZW50X3BlcmlvZCArIGhfaW50ZXJ2YWwgLyAyICAjIGluaXRpYWwgY29uZGl0aW9uIChpbml0aWFsIHRpbWUsIHRfYWJzID0gc3RhcnRfdCkKICBlbmRfdGltZSA8LSB0YXUKICAKICBmb3IoaiBpbiAxOmRpbSkgewogICAgdCA8LSB0emVybyAjaW5pdGlhbGl6ZSB0aW1lIGZvciBlYWNoIG9mIGRpZmZlcmVudCBpbml0aWFsIHBlcnR1cmJhdGlvbnMKICAgIGZvcihpIGluIDE6YXMuaW50ZWdlcihlbmRfdGltZSAvIGRlbHRhdCkpewogICAgbnZfbGluZWFyX3BbLCBqXSA8LSByazQobnZfbGluZWFyX3BbLCBqXSwgcmVmX2RhdGEsIHQsIGhfaW50ZXJ2YWwsIGRpbSwgZGlmZl92ZWMpCiAgICB0IDwtIHQgKyBoX2ludGVydmFsICMgdXBkYXRlIHRpbWUgKHN0YXJ0aW5nIGZyb20gdGhlIG1pZGRsZSkKICAgIH0KICB9CiAgICAKICByZXR1cm4obnZfbGluZWFyX3AvZGVsdGF4KQp9CgojVGhpcyBpcyBhIGZ1bmN0aW9uIHRoYXQgZGlyZWN0bHkgdXNlZCB0aGUgbm9ubGluZWFyIE9ERSB3aXRoIHRoZSBwZXJ0dXJiZWQgaW5pdGlhbCBjb25kaXRpb25zCmRpcmVjdF9jb2VmZiA8LSBmdW5jdGlvbihyZWZfZGF0YSwgZGVsdGF4LCBzdGFydF90LCB0YXUsIGhfaW50ZXJ2YWwsIGRpbSwgZGlmZl92ZWMpIHsKICAjbWF0cml4IHRvIHN0b2NrIHJlc3VsdHMKICBudl9ub25saW5lYXJfcCA8LSBtYXRyaXgoMCwgbnJvdyA9IGRpbSwgbmNvbCA9IGRpbSkKICAKICB0emVybyA8LSBzdGFydF90IC0gdHJhbnNpZW50X3BlcmlvZCArIGhfaW50ZXJ2YWwgLyAyICAjIGluaXRpYWwgY29uZGl0aW9uIChpbml0aWFsIHRpbWUsIHRfYWJzID0gc3RhcnRfdCkKICB0X2luZGV4X3N0YXJ0IDwtIGFzLmludGVnZXIoKHR6ZXJvIC8gaF9pbnRlcnZhbCkgKiAyKQogIHRfaW5kZXhfZW5kIDwtIHRfaW5kZXhfc3RhcnQgKyBhcy5pbnRlZ2VyKCh0YXUgLyBoX2ludGVydmFsKSAqIDIpCiAgI0luaXRpYWwgY29uZGl0aW9uIAogIG52X25vbmxpbmVhcl9wWywgal9QMV0gPC0gYXMubnVtZXJpYyhyZWZfZGF0YVt0X2luZGV4X3N0YXJ0LCAtMV0pICsgYyhkZWx0YXgsIDAsIDAsIDAsIDApCiAgbnZfbm9ubGluZWFyX3BbLCBqX1AyXSA8LSBhcy5udW1lcmljKHJlZl9kYXRhW3RfaW5kZXhfc3RhcnQsIC0xXSkgKyBjKDAsIGRlbHRheCwgMCwgMCwgMCkKICBudl9ub25saW5lYXJfcFssIGpfQzFdIDwtIGFzLm51bWVyaWMocmVmX2RhdGFbdF9pbmRleF9zdGFydCwgLTFdKSArIGMoMCwgMCwgZGVsdGF4LCAwLCAwKQogIG52X25vbmxpbmVhcl9wWywgal9DMl0gPC0gYXMubnVtZXJpYyhyZWZfZGF0YVt0X2luZGV4X3N0YXJ0LCAtMV0pICsgYygwLCAwLCAwLCBkZWx0YXgsIDApCiAgbnZfbm9ubGluZWFyX3BbLCBqX1JdIDwtIGFzLm51bWVyaWMocmVmX2RhdGFbdF9pbmRleF9zdGFydCwgLTFdKSArIGMoMCwgMCwgMCwgMCwgZGVsdGF4KQogIAogIGVuZF90aW1lIDwtIHRhdQogIAogI3JrNChpbl92ZWMgPSBudl9yazQsIHRpbWUgPSB0LCBoX2ludGVydmFsID0gZGVsdGF0LCBkaW0gPSBkaW1fbW9kZWwxLCBkaWZmX3ZlYyA9IGRpZmZfNXNwKQogIAogIGZvcihqIGluIDE6ZGltKSB7CiAgICB0IDwtIHR6ZXJvCiAgICBmb3IoaSBpbiAxOmFzLmludGVnZXIoZW5kX3RpbWUgLyBkZWx0YXQpKXsKICAgIG52X25vbmxpbmVhcl9wWywgal0gPC0gcms0KG52X25vbmxpbmVhcl9wWywgal0sIHJlZl9kYXRhID0gTlVMTCwgdCwgaF9pbnRlcnZhbCwgZGltLCBkaWZmX3ZlYykKICAgIHQgPC0gdCArIGhfaW50ZXJ2YWwgIyB1cGRhdGUgdGltZSAoc3RhcnRpbmcgZnJvbSB0aGUgbWlkZGxlKQogICAgfQogIH0KICAKICAjQ2FsY3VsYXRlIHRoZSBkaWZmZXJlbmNlIGJldHdlZW4gdGhlIHBlcnR1cmJlZCBmbG93IGFuZCB1bnBlcnR1cmJlZCBmbG93CiAgZm9yKGogaW4gMTpkaW0pIG52X25vbmxpbmVhcl9wWywgal0gPC0gbnZfbm9ubGluZWFyX3BbLCBqXSAtIGFzLm51bWVyaWMocmVmX2RhdGFbdF9pbmRleF9lbmQsIC0xXSkgIAogIAogIHJldHVybihudl9ub25saW5lYXJfcC9kZWx0YXgpCn0KYGBgCgojIyMjIyBbOC4yLjRdIExpbmVhcml6ZWQgbW9kZWwgZm9yIGNhbGN1bGF0aW5nIGFsbCBwb2ludHMgZnJvbSAxMDAwIHRvIDIwMDAgd2l0aCBpbnRlcnZhbCB0YXUgPSA1ClRoZSByZWZlcmVuY2UgdGltZSBwb2ludHMgYXJlIGV2ZXJ5IHRhdSAoPSA1LjApLCBidXQgdGhlIHByZWNpc2VfY29lZmYgd2FzIGNhbGN1bGF0ZWQgZm9yIG1hbnkgc2NlbmFyaW9zICg1LjAsIDAuMDEsIDAuNSwgMS4wLCAyLjAsIDEwLjApCmBgYHtyfQpwcmVjaXNlX2NvZWZmXzVzcCA8LSBsaXN0KCkKaW5zdF9wcmVjaXNlX2NvZWZmXzVzcCA8LSBsaXN0KCkKc3RhcnRfdGltZSA8LSB2ZWN0b3IoKQoKdGF1IDwtIDUKdGF1MSA8LSA1CgpwcmVjaXNlX2NvZWZmXzVzcCA8LSBtY2xhcHBseSgxOjIwMCwgZnVuY3Rpb24oaSkgewogIHN0YXJ0X3RpbWVbaV0gPC0gdHJhbnNpZW50X3BlcmlvZCArIChpIC0gMSkqdGF1CiAgcmVzdWx0X2xpbmVhciA8LSBwcmVjaXNlX2NvZWZmKHJrNF9yZXN1bHRfZmluZSwgZGVsdGF4ID0gMC4wMDAxLCBzdGFydF90ID0gc3RhcnRfdGltZVtpXSwgdGF1MSwgZGVsdGF0LCBkaW0gPSA1LCBkaWZmX0xfNXNwKQogIHJlc3VsdF9saW5lYXIKfSwgbWMuY29yZXMgPSAxNikKCnRhdTIgPC0gMC4wMQppbnN0X3ByZWNpc2VfY29lZmZfNXNwIDwtIG1jbGFwcGx5KDE6MjAwLCBmdW5jdGlvbihpKSB7CiAgc3RhcnRfdGltZVtpXSA8LSB0cmFuc2llbnRfcGVyaW9kICsgKGkgLSAxKSp0YXUKICByZXN1bHRfbGluZWFyIDwtIHByZWNpc2VfY29lZmYocms0X3Jlc3VsdF9maW5lLCBkZWx0YXggPSAwLjAwMDEsIHN0YXJ0X3QgPSBzdGFydF90aW1lW2ldLCB0YXUyLCBkZWx0YXQsIGRpbSA9IDUsIGRpZmZfTF81c3ApCiAgcmVzdWx0X2xpbmVhcgp9LCBtYy5jb3JlcyA9IDE2KQoKdGF1MyA8LSAwLjUKdGF1MC41X3ByZWNpc2VfY29lZmZfNXNwIDwtIG1jbGFwcGx5KDE6MjAwLCBmdW5jdGlvbihpKSB7CiAgc3RhcnRfdGltZVtpXSA8LSB0cmFuc2llbnRfcGVyaW9kICsgKGkgLSAxKSp0YXUKICByZXN1bHRfbGluZWFyIDwtIHByZWNpc2VfY29lZmYocms0X3Jlc3VsdF9maW5lLCBkZWx0YXggPSAwLjAwMDEsIHN0YXJ0X3QgPSBzdGFydF90aW1lW2ldLCB0YXUzLCBkZWx0YXQsIGRpbSA9IDUsIGRpZmZfTF81c3ApCiAgcmVzdWx0X2xpbmVhcgp9LCBtYy5jb3JlcyA9IDE2KQoKdGF1NCA8LSAxLjAKdGF1MS4wX3ByZWNpc2VfY29lZmZfNXNwIDwtIG1jbGFwcGx5KDE6MjAwLCBmdW5jdGlvbihpKSB7CiAgc3RhcnRfdGltZVtpXSA8LSB0cmFuc2llbnRfcGVyaW9kICsgKGkgLSAxKSp0YXUKICByZXN1bHRfbGluZWFyIDwtIHByZWNpc2VfY29lZmYocms0X3Jlc3VsdF9maW5lLCBkZWx0YXggPSAwLjAwMDEsIHN0YXJ0X3QgPSBzdGFydF90aW1lW2ldLCB0YXU0LCBkZWx0YXQsIGRpbSA9IDUsIGRpZmZfTF81c3ApCiAgcmVzdWx0X2xpbmVhcgp9LCBtYy5jb3JlcyA9IDE2KQoKdGF1NSA8LSAyLjAKdGF1Mi4wX3ByZWNpc2VfY29lZmZfNXNwIDwtIG1jbGFwcGx5KDE6MjAwLCBmdW5jdGlvbihpKSB7CiAgc3RhcnRfdGltZVtpXSA8LSB0cmFuc2llbnRfcGVyaW9kICsgKGkgLSAxKSp0YXUKICByZXN1bHRfbGluZWFyIDwtIHByZWNpc2VfY29lZmYocms0X3Jlc3VsdF9maW5lLCBkZWx0YXggPSAwLjAwMDEsIHN0YXJ0X3QgPSBzdGFydF90aW1lW2ldLCB0YXU1LCBkZWx0YXQsIGRpbSA9IDUsIGRpZmZfTF81c3ApCiAgcmVzdWx0X2xpbmVhcgp9LCBtYy5jb3JlcyA9IDE2KQoKdGF1NiA8LSAxMC4wCnRhdTEwLjBfcHJlY2lzZV9jb2VmZl81c3AgPC0gbWNsYXBwbHkoMToyMDAsIGZ1bmN0aW9uKGkpIHsKICBzdGFydF90aW1lW2ldIDwtIHRyYW5zaWVudF9wZXJpb2QgKyAoaSAtIDEpKnRhdQogIHJlc3VsdF9saW5lYXIgPC0gcHJlY2lzZV9jb2VmZihyazRfcmVzdWx0X2ZpbmUsIGRlbHRheCA9IDAuMDAwMSwgc3RhcnRfdCA9IHN0YXJ0X3RpbWVbaV0sIHRhdTYsIGRlbHRhdCwgZGltID0gNSwgZGlmZl9MXzVzcCkKICByZXN1bHRfbGluZWFyCn0sIG1jLmNvcmVzID0gMTYpCgoKcHJlY2lzZV9jb2VmZl81c3BbWzVdXQppbnN0X3ByZWNpc2VfY29lZmZfNXNwW1s1XV0KdGF1MC41X3ByZWNpc2VfY29lZmZfNXNwW1s1XV0KCiNzYXZlUkRTKHByZWNpc2VfY29lZmZfNXNwLCAiZGVmYXVsdF9wcmVjaXNlX2NvZWZmXzVzcC5vYmoiKQpgYGAKIyMjIyMgWzguMi41XSBOb25saW5lYXIgT0RFIG1vZGVsIGZvciBjYWxjdWxhdGluZyBhbGwgcG9pbnRzIGZyb20gMTAwMCB0byAyMDAwIHdpdGggaW50ZXJ2YWwgdGF1ID0gNQpgYGB7cn0KZGlyZWN0X2NvZWZmXzVzcCA8LSBsaXN0KCkKCnN0YXJ0X3RpbWUgPC0gdmVjdG9yKCkKdHJhbnNpZW50X3BlcmlvZCA8LSAxMDAwCgpkaXJlY3RfY29lZmZfNXNwIDwtIG1jbGFwcGx5KDE6MjAwLCBmdW5jdGlvbihpKSB7CiAgc3RhcnRfdGltZVtpXSA8LSB0cmFuc2llbnRfcGVyaW9kICsgKGkgLSAxKSp0YXUKICByZXN1bHRfbm9ubGluZWFyIDwtIGRpcmVjdF9jb2VmZihyazRfcmVzdWx0X2ZpbmUsIGRlbHRheCA9IDAuMDAwMSwgc3RhcnRfdCA9IHN0YXJ0X3RpbWVbaV0sIHRhdSwgZGVsdGF0LCBkaW0gPSA1LCBkaWZmXzVzcCkKICByZXN1bHRfbm9ubGluZWFyCn0sIG1jLmNvcmVzID0gMTYpCgpkaXJlY3RfY29lZmZfNXNwW1s1XV0KYGBgCkNvbXBhcmlzb24gYmV0d2VlbiB0aGUgbGluZWFyaXplZCBPREUgYW5kIG5vbmxpbmVhciBPREUKYGBge3J9CihwcmVjaXNlX2NvZWZmXzVzcFtbNV1dIC0gZGlyZWN0X2NvZWZmXzVzcFtbNV1dKS9kaXJlY3RfY29lZmZfNXNwW1s1XV0KYGBgCiMjIyBbOV0gTURSIFMtbWFwCkFwcGx5aW5nIE1EUiBTLW1hcCB0byB0aGUgNXNwIGNvdXBsZWQgZm9vZGNoYWluIG1vZGVsCgojIyMjIFs5LjFdIERhdGEgcHJlYXJyYW5nZW1lbnQKUmVhZCBkYXRhc2V0CmBgYHtyfQpkYS5yYW5nZSA8LSAxOjIwMCAjIFN1YnNhbXBsZSBmb3IgZGF0YSBhbmFseXNpcwpvdXQuc2FtcGxlIDwtIFQgIyBUL0YgZm9yIG91dC1vZi1zYW1wbGUgZm9yZWNhc3QKbm91dCA8LSAyICAjIG51bWJlciBvZiBvdXQtb2Ytc2FtcGxlCgpkYS5uYW1lIDwtICc1cF9tb2RlbCcKZG8gPC0gcmVhZFJEUygicms0X3Jlc3VsdF81c3BfbW9kZWwub2JqIikKZG90IDwtIGRvW2RhLnJhbmdlLCAxXSAjIGRhdGEgdGltZQpkbyA8LSBkb1tkYS5yYW5nZSwgLTFdICMgc3Vic2V0IG9mIGRhdGEgd2l0aG91dCB0Cm5kbyA8LSBucm93KGRvKQpuaW4gPC0gbmRvIC0gbm91dCAjIGxpYnJhcnkgc2FtcGxlIHNpemUKYGBgClN0YW5kYXJkaXphdGlvbgpgYGB7cn0KIyBJbi1zYW1wbGUKZG8ubWVhbiA8LSBhcHBseShkb1sxOm5pbiwgXSwgMiwgbWVhbiwgbmEucm0gPSBUKSAgIyBtZWFuIGFidW5kYW5jZSBpbiBpbi1zYW1wbGUKZG8uc2QgPC0gYXBwbHkoZG9bMTpuaW4sIF0sIDIsIHNkLCBuYS5ybSA9IFQpICAgICAgIyBTRCBvZiBhYnVuZGFuY2UgaW4gaW4tc2FtcGxlCmQgPC0gZG9bMToobmluLTEpLCBdICAgICAgICAgICAgICAgICAgICAgICAgICAjIEluLXNhbXBsZSBkYXRhc2V0IGF0IHRpbWUgdApkX3RwMSA8LSBkb1syOihuaW4pLCBdICAgICAgICAgICAgICAgICAgICAgICAgIyBJbi1zYW1wbGUgZGF0YXNldCBhdCB0aW1lIHQrMQpkcyA8LSAoZCAtIHJlcG1hdChkby5tZWFuLCBucm93KGQpLCAxKSkqcmVwbWF0KGRvLnNkLCBucm93KGQpLCAxKSBeIC0xICMgTm9ybWFsaXplZCBpbi1zYW1wbGUgZGF0YXNldCBhdCB0aW1lIHQKZHNfdHAxIDwtIChkX3RwMSAtIHJlcG1hdChkby5tZWFuLCBucm93KGRfdHAxKSwgMSkpKnJlcG1hdChkby5zZCwgbnJvdyhkX3RwMSksIDEpIF4gLTEgIyBOb3JtYWxpemVkIGluLXNhbXBsZSBkYXRhc2V0IGF0IHRpbWUgdCsxCgojIE91dC1zYW1wbGUKaWYob3V0LnNhbXBsZSAmIG5vdXQgIT0gMCl7CiAgZC50ZXN0IDwtIGRvW25pbjoobmRvIC0gMSksIF0gICAgICAgICAgICAgICAgICMgT3V0LW9mLXNhbXBsZSBkYXRhc2V0IGF0IHRpbWUgdCAKICBkdF90cDEgPC0gZG9bKG5pbiArIDEpOiBuZG8sIF0gICAgICAgICAgICAgICAgICMgT3V0LW9mLXNhbXBsZSBkYXRhc2V0IGF0IHRpbWUgdCsxCiAgZHMudGVzdCA8LSAoZC50ZXN0IC0gcmVwbWF0KGRvLm1lYW4sIG5yb3coZC50ZXN0KSwgMSkpKnJlcG1hdChkby5zZCwgbnJvdyhkLnRlc3QpLCAxKSBeIC0xICMgTm9ybWFsaXplZCBvdXQtb2Ytc2FtcGxlIGRhdGFzZXQgYXQgdGltZSB0CiAgZHN0X3RwMSA8LSAoZHRfdHAxIC0gcmVwbWF0KGRvLm1lYW4sIG5yb3coZHRfdHAxKSwgMSkpKnJlcG1hdChkby5zZCwgbnJvdyhkdF90cDEpLCAxKSBeIC0xICMgTm9ybWFsaXplZCBvdXQtb2Ytc2FtcGxlIGRhdGFzZXQgYXQgdGltZSB0KzEKfWVsc2V7ZC50ZXN0IDwtIGR0X3RwMSA8LSBkcy50ZXN0IDwtIE5VTEx9CgojIENvbXBpbGVkIGRhdGEgYXQgdGltZSB0IApkcy5hbGwgPC0gcmJpbmQoZHMsIGRzLnRlc3QpCmhlYWQoZHMuYWxsKQpgYGAKSW5pdGlhbGl6YXRpb24gb2YgcHNldWRvLXJhbmRvbSBudW1uYmVyIGdlbmVyYXRvcgpgYGB7cn0Kc2VlZCA8LSA0OTU2MwpzZXQuc2VlZChzZWVkKQpgYGAKCgojIyMjIFs5LjJdIE9wdGltYWwgZW1iZWRkaW5nIGRpbWVuc2lvbgpGaW5kIHRoZSBvcHRpbWFsIGVtYmVkZGluZyBkaW1lbnNpb24sIGJhc2VkIG9uIHVuaXZhcmlhdGUgc2ltcGxleCBwcm9qZWN0aW9uCmBgYHtyIHdhcm5pbmcgPSBGQUxTRX0KRW1heCA8LSA1ICMgZXF1YWwgdG8gb3Igc21hbGxlciB0aGFuIHRoZSBudW1iZXIgb2Ygbm9kZXMgKGRpbWVuc2lvbiBvZiB0aGUgT0RFIHN5c3RlbSkKY3JpIDwtICdybXNlJyAjIG1vZGVsIHNlbGVjdGlvbiAKRWQgPC0gTlVMTApmb3JlY2FzdF9za2lsbF9zaW1wbGV4IDwtIE5VTEwKZm9yKGkgaW4gMTpuY29sKGRzKSl7CiAgc3B4LmkgPC0gc2ltcGxleChkc1ssIGldLCBFID0gMjpFbWF4KQogIEVkIDwtIGMoRWQsIHNweC5pW3doaWNoLm1pbihzcHguaVssIGNyaV0pWzFdLCAnRSddKQogIGZvcmVjYXN0X3NraWxsX3NpbXBsZXggPC0gYyhmb3JlY2FzdF9za2lsbF9zaW1wbGV4LCBzcHguaVt3aGljaC5taW4oc3B4LmlbLCBjcmldKVsxXSwgJ3JobyddKQp9CkVkICMgVGhlIG9wdGltYWwgZW1iZWRkaW5nIGRpbWVuc2lvbiBmb3IgZWFjaCB2YXJpYWJsZQpgYGAKT3B0aW1hbCBlbWJlZGRpbmcgZGltZW5zaW9uIGFuZCBmb3JlY2FzdGluZyBza2lsbApgYGB7cn0KRWQKZm9yZWNhc3Rfc2tpbGxfc2ltcGxleAoKYGBgCiMjIyMgWzkuM10gQ0NNIGFuYWx5c2lzCiogRmluZCBjYXVzYWwgdmFyaWFibGVzIGJ5IENDTSBhbmFseXNpcyB0aGF0IHdpbGwgYmUgdXNlZCBmb3IgbXVsdGl2aWV3IGVtYmVkZGluZy4KCiogV2FybmluZzogSXQgaXMgdGltZSBjb25zdW1pbmcgZm9yIGNhbGN1bGF0aW5nIHRoZSBjYXVzYXRpb24gZm9yIGVhY2ggbm9kZQoKKiBDQ00gY2F1c2FsaXR5IHRlc3QgZm9yIGFsbCBub2RlIHBhaXJzICh0aGUgZnVuY3Rpb24gd2FzIHVwZGF0ZWQgYXQgMjAyNC8wNS8wNykKYGBge3Igd2FybmluZyA9IEZBTFNFfQpjY20ub3V0IDwtIGNjbS5mYXN0LmRlbW8oZHMsIEVwYWlyID0gVCwgY3JpID0gY3JpLCBFbWF4ID0gRW1heCkKY2NtLnNpZyA8LSBjY20ub3V0W1snY2NtLnNpZyddXQpjY20ucmhvIDwtIGNjbS5vdXRbWydjY20ucmhvJ11dCiNUbyBhdm9pZCBvdmVyd3JpdGUgdGhlIG9yaWdpbmFsIGZpbGVzLCB3ZSBzYXZlIHRoZW0gd2l0aCBkaWZmZXJlbnQgbmFtZXMsaWRlbnRpZmllZCBieSBkYXRlLgpEQVkgPSBTeXMuRGF0ZSgpCnNhdmVSRFMoY2NtLnNpZywgcGFzdGUoJ2NjbV9zaWcnLCBkYS5uYW1lLCduaW4nLCBuaW4sIERBWSwgJy5vYmonLCBzZXAgPSAnXycpKQpzYXZlUkRTKGNjbS5yaG8sIHBhc3RlKCdjY21fcmhvJywgZGEubmFtZSwnbmluJywgbmluLCBEQVksICdkZW1vLm9iaicsIHNlcCA9ICdfJykpCmBgYApKdXN0IGluIGNhc2Ugbm90IGNvbmR1Y3RpbmcgQ0NNIGJ1dCBqdXN0IGxvYWRpbmcgdGhlIHJlc3VsdCBvZiBDQ00gYXQgMjAyNC8wNC8yNwpgYGB7cn0KREFZID0gIjIwMjQtMDQtMjciCiNjY20uc2lnX29sZCA8LSByZWFkUkRTKHBhc3RlKCdjY21fc2lnJywgZGEubmFtZSwnbmluJywgbmluLCBEQVksICcub2JqJywgc2VwID0gJ18nKSkgCiNjY20ucmhvX29sZCA8LSByZWFkUkRTKHBhc3RlKCdjY21fcmhvJywgZGEubmFtZSwnbmluJywgbmluLCBEQVksICdkZW1vLm9iaicsIHNlcCA9ICdfJykpCmBgYAoKYGBge3J9CmNjbS5zaWcKI2NjbS5zaWdfb2xkCmNjbS5yaG8KI2NjbS5yaG9fb2xkCmBgYAojIyMjIFs5LjRdIE11bHRpdmlldyBkaXN0YW5jZQojIyMjIyBbOS40LjFdIFBlcmZvcm1pbmcgbXVsdGl2aWV3IGFuYWx5c2lzCkJhc2VkIG9uIHRoZSBjYXVzYWwgdmFyaWFibGVzIGRldGVjdGVkIGluIENDTSwKCigxKSBnZW5lcmF0ZXMgdGhlIHRpbWUgbGFnIHNlcmllcyAod2l0aCBtYXhpbXVtIGxhZyA9IDMpLAoKKDIpIGNvbmR1Y3QgbXVsdGl2YXJpYXRlIHNpbXBsZXggcHJvamVjdGlvbiBhbmQgZXZhbHVhdGUgdGhlIGZvcmVjYXN0IHNraWxsLCBhbmQKCigzKSBzZWxlY3RlZCB0aGUgYmVzdCBrbig9MTAwKSBTU1IuCgpQZXJmb3JtIG11bHRpdmlldyBlbWJlZGRpbmcgYW5hbHlzaXMgZm9yIGVhY2ggbm9kZQoKV2FybmluZzogSXQgaXMgdGltZSBjb25zdW1pbmcgZm9yIHJ1bm5pbmcgbXVsdGl2aWV3IGVtYmVkZGluZyBmb3IgZWFjaCBub2RlcwpgYGB7ciB3YXJuaW5nID0gRkFMU0V9CmVzZWxlX2xhZyA8LSBlc2ltLmxhZy5kZW1vKGRzLCBjY20ucmhvLCBjY20uc2lnLCBFZCwga21heCA9IDEwMDAwLCBrbiA9IDEwMCwgbWF4X2xhZyA9IDMsIEVtYXggPSBFbWF4KQojIFRvIGF2b2lkIG92ZXJ3cml0ZSB0aGUgb3JpZ2luYWwgZmlsZXMsIHdlIHNhdmUgdGhlbSB3aXRoIGRpZmZlcmVudCBuYW1lcywgJ1hYWF9ORVcnLgpEQVkgPSBTeXMuRGF0ZSgpCnNhdmVSRFMoZXNlbGVfbGFnLCBwYXN0ZSgnZXNlbGVMYWcnLCBkYS5uYW1lLCAnbmluJywgbmluLCBEQVksICdkZW1vLm9iaicsIHNlcD0nXycpKQpgYGAKVGhlIGxpc3Qgb2YgdGhlIHNlbGVjdGVkIGJlc3QgbXVsdGl2YXJpYXRlIFNTUnMgZm9yIGVhY2ggbm9kZSAoc3BlY2llcywgc3ApIHdpdGgKCigxKSB0aGUgY29ycmVsYXRpb24gY29lZmZpY2llbnQgKHJobykKCigyKSB0aGUgbGlzdCBvZiB2YXJpYWJsZXMgKFhfMSwgWF8yLCDigKYpIHVzZWQgaW4gZWFjaCBTU1IsIG5vdGluZyB0aGF0IHRoZSBudW1iZXIgb2YgdmFyaWFibGVzIGlzIGlkZW50aWNhbCB0byB0aGUgb3B0aW1hbCBlbWJlZGRpbmcgZGltZW5zaW9uIG9idGFpbmVkIGluIFs2LjJdLCBhbmQKCigzKSB0aGUgbGlzdCBvZiB0aW1lIGxhZ3MgKHZsYWdfMSwgdmxhZ18yLCDigKYpIHVzZWQgaW4gdGhlIGNvcnJlc3BvbmRpbmcgdmFyaWFibGVzIChYXzEsIFhfMiwg4oCmKS4KYGBge3J9CmFzLmRhdGEuZnJhbWUoZXNlbGVfbGFnKQpgYGAKIyMjIyMgWzkuNC4yXSBDb21wdXRlIG11bHRpdmlldyBkaXN0YW5jZQpgYGB7cn0KZG1hdHJpeC5tdiA8LSBtdmRpc3QuZGVtbyhkcywgZHMuYWxsLCBlc2VsZV9sYWcpCmRtYXRyaXgudHJhaW4ubXZ4IDwtIGRtYXRyaXgubXZbWydkbWF0cml4LnRyYWluLm12eCddXQpkbWF0cml4LnRlc3QubXZ4IDwtIGRtYXRyaXgubXZbWydkbWF0cml4LnRlc3QubXZ4J11dCmBgYApMZWF2ZS1vbmUtb3V0IGNyb3NzLXZhbGlkYXRpb24gZm9yIGZpbmRpbmcgdGhlIG9wdGltYWwgcGFyYW1ldGVycyBmb3IgTURSIFMtbWFwIGFuYWx5c2lzCgrigJNXYXJuaW5nOiBUaGUgY3Jvc3MtdmFsaWRhdGlvbiBpcyB0aGUgbW9zdCB0aW1lLWNvbnN1bWluZyBzdGVwIGluIE1EUiBTLW1hcCByZXF1aXJpbmcgbWFzc2l2ZSBjb21wdXRhdGlvbnMgYW5kIC4gVGh1cywgd2UgcmVjb21tZW5kIGRpdmlkaW5nIGpvYiBpbnRvIHNtYWxsZXIgcGFydHMgKHN1Yi5kYT4xKSBvciB1c2VkIHBhcmFsbGVsIGNvbXB1dGF0aW9uIChwYXJhbGw9VCwgbmNvcmU+PTEpCmBgYHtyLCB3YXJuaW5nID0gRkFMU0V9CmRvLk1EUi5DViA8LSBUCiMjIyBUaGUgcGFyYW1ldGVyIGN2LnVuaXQgZGV0ZXJtaW5lcyB0aGUgcHJlY2lzaW9uIG9mIHNlbGVjdGVkIHBhcmFtZXRlcnMgYW5kIHN0cm9uZ2x5IGluZmx1ZW5jZXMgY29tcHV0YXRpb24gdGltZS4KIyMjIEluIG91ciBjYXNlcywgd2UgdXNlZCBjdi51bml0PTAuMDI1IHRvIG9idGFpbiBtb3JlIHByZWNpc2UgZXN0aW1hdGlvbnMKIyMjIFRoaXMgcGFyYW1ldGVyIG1heSBiZSBhZGp1c3RlZCB0byAwLjA1IG9yIGV2ZW4gMC4xLCBkZXBlbmRpbmcgb24gaG93IHNlbnNpdGl2ZSB0aGUgcmVzdWx0cyB0byBwYXJhbWV0ZXIgcHJlY2lzaW9uLiAKY3YudW5pdCA8LSAwLjAyNQphbHBoYS5zbyA8LSBzZXEoMCwgMSwgY3YudW5pdCk7ICAgICAgICAgICAgIyBTZXF1ZW5jZSBvZiBhbHBoYQpzdWIuZGEgPC0gMSAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgIyBEaXZpZGUgdGhlIGNvbXB1dGF0aW9uIGpvYiBpbnRvIGZpdmUgcGFydHMgCmFmc3AgPC0gZXFzcGxpdCgxOmxlbmd0aChhbHBoYS5zbyksIHN1Yi5kYSkgIyBEaXZpZGUgdGhlIHBhcmFtZXRlciBzcGFjZSBiYXNlZCBvbiBhbHBoYSBwYXJhbWV0ZXIKYWxmIDwtIDEgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICMgUnVuIENWIGluIHRoZSBmaXJzdCBwYXJhbWV0ZXIgc3Vic2V0IAoKIyBDcm9zcy12YWxpZGF0aW9uIG9mIE1EUiBhbmFseXNpcyAgICAKaWYoZG8uTURSLkNWKXsKICBhbHBoYS5zIDwtIGFscGhhLnNvW2Fmc3BbYWxmLCAxXTphZnNwW2FsZiwgMl1dICMgU3Vic2V0IHBhcmFtZXRlciBzcGFjZQogIGN2LmluZCA8LSBjdi5NRFIuZGVtbyhkcywgZHNfdHAxLCBkbWF0cml4Lmxpc3QgPSBkbWF0cml4LnRyYWluLm12eCwgCiAgICAgICAgICAgICAgICAgICAgICAgIHBhcmFsbCA9IFQsIG5jb3JlID0gMjQsIGtlZXBfaW50cmEgPSBULCBhbHBoYS5zZXEgPSBhbHBoYS5zKQogICMgVG8gYXZvaWQgb3ZlcndyaXRlIHRoZSBvcmlnaW5hbCBmaWxlcywgd2Ugc2F2ZSB0aGVtIHdpdGggZGlmZmVyZW50IG5hbWVzLCAnWFhYX05FVycuCiAgc2F2ZVJEUyhjdi5pbmQsIHBhc3RlKGRhLm5hbWUsICduaW4nLCBuaW4sICdjdnVuaXQnLCBjdi51bml0LCAnYWxwaCcsIGFscGhhLnNbMV0qMTAwLCBEQVksICdjdm91dF9ObXZ4X1JhbGx4Lm9iaicsIHNlcCA9ICdfJykpCn0KYGBgCgojIyMjIyBbOS40LjNdIFNlbGVjdGluZyB0aGUgb3B0aW1hbCBwYXJhbWV0ZXJzClNlbGVjdCB0aGUgb3B0aW1hbCBwYXJhbWV0ZXIgc2V0IGZvciByZWd1bGFyaXplZCByZWdyZXNzaW9uIG1vZGVsIHdpdGggdGhlIG1pbmltYWwgTVNFCgpgYGB7cn0KcGFyYWN2LmRlbW8gPC0gc2Vjdi5kZW1vKGN2LmluZCkKcGFyYWN2LmRlbW8KYGBgCiMjIyMgWzkuNV0gTURSIFMtbWFwCkZpdHRpbmcgTURSIFMtbWFwIGJhc2VkIG9uIHRoZSBwYXJhbWV0ZXJzIHNlbGVjdGVkIGJ5IENWCgpOb3RlIHRoYXQgdGhlIGxpbmVhciByZWdyZXNzaW9uIG1vZGVsIGluIE1EUiBTLW1hcCBpbmNsdWRlcyBhbGwgb2YgdmFyaWFibGVzIGFzIFggZXZlbiBpZiBzb21lIG9mIHRoZW0gd2VyZSBub3Qgc2VsZWN0ZWQgYXMgdGhlIGNhdXNhbCB2YXJpYWJsZXMgYXQgdGhlIHN0ZXAgb2YgdXNpbmcgQ0NNLiBUaGlzIGlzIHJlYXNvbmFibGUgYmVjYXVzZSBTLW1hcCBjb2VmZmljaWVudHMgcmVwcmVzZW50IHRoZSBlZmZlY3RzIG9mIHZhcmlhYmxlcyBhdCBzaG9ydCB0aW1lc2NhbGUgd2hpbGUgQ0NNIGV2YWx1YXRlcyB0aGUgY2F1c2FsaXR5IGluIHRoZSB3aG9sZSBwZXJpb2Qgb2YgdGhlIHRpbWUgc2VyaWVzLiAKYGBge3J9CiNTZXR0aW5nCmRvLk1EUiA8LSBGCmN2LnVuaXQgPC0gMC4wMjUgICAgICAgICAgICAgICAgICAgICAgICAgICAKcHR5cGUgPC0gJ2FlbmV0JyAgICAgICAgICAjZW5ldDplbGFzdGljLW5ldCBvciBtc2FlbmV0OiBhZGFwdGl2ZSBlbGFzdGljLW5ldAoKI0ZpdHRpbmcgdGhlIE1EUiBTLW1hcApzbWFwLjVzcCA8LSBNRFJzbWFwLmRlbW8ocGFyYWN2ID0gcGFyYWN2LmRlbW8sIHB0eXBlID0gcHR5cGUsIGtlZXBfaW50cmEgPSBULCBvdXQuc2FtcGxlID0gVCwKICAgICAgICAgICAgICAgICAgICAgICAgICAgIGRzLGRzX3RwMSxkcy50ZXN0LGRzdF90cDEsCiAgICAgICAgICAgICAgICAgICAgICAgICAgICBkbWF0cml4Lmxpc3QgPSBkbWF0cml4LnRyYWluLm12eCwKICAgICAgICAgICAgICAgICAgICAgICAgICAgIGRtYXRyaXgudGVzdC5saXN0ID0gZG1hdHJpeC50ZXN0Lm12eCkKYGBgCgpJbiBjYXNlIGZvciBzYXZpbmcgdGhlIHJlc3VsdHMKYGBge3J9CkRBWSA9IFN5cy5EYXRlKCkKbnIub3V0IDwtIHNtYXAuNXNwW1snbnIub3V0J11dOwoKICBzYXZlUkRTKG5yLm91dCwgcGFzdGUoZGEubmFtZSwnX25pbicsIG5pbiwgJ2N2dW5pdCcsIGN2LnVuaXQsIHB0eXBlLCBEQVksICducm91dF9ObXZ4X1JhbGx4X2RlbW9fTkVXLm9iaicsc2VwID0gJ18nKSkKICAgICMgU2F2ZSBpbnRlcmFjdGlvbiBKYWNvYmlhbiBtYXRyaWNlcyBhdCBhbGwgdGltZSBwb2ludHMKICBzYXZlUkRTKHNtYXAuNXNwW1snamNvZiddXSwgcGFzdGUoZGEubmFtZSwnbmluJywgbmluLCAnY3Z1bml0JywgY3YudW5pdCwgcHR5cGUsIERBWSwgJ19qY29mX05tdnhfUmFsbHhfZGVtb19ORVcub2JqJywgc2VwPSdfJykpCgpgYGAKClMtbWFwIGNvZWZmaWNpZW50cwpgYGB7cn0Kc21hcC41c3BbWydqY29mJ11dCiNvcgojIjVwX21vZGVsX25pbl8xOThfY3Z1bml0XzAuMDI1X2FlbmV0XzIwMjQtMDctMTlfX2pjb2ZfTm12eF9SYWxseF9kZW1vX05FVy5vYmoiCmBgYAoKIyMjIFsxMF0gQ29tcGFyaXNvbnMgZm9yIDVzcCBtb2RlbApMb2FkaW5nIGRhdGEKYGBge3J9CnNtYXAuNXNwIDwtIGxpc3QoKQpzbWFwLjVzcFtbJ2pjb2YnXV0gPC0gcmVhZFJEUygiNXBfbW9kZWxfbmluXzE5OF9jdnVuaXRfMC4wMjVfYWVuZXRfMjAyNC0wNy0xOV9famNvZl9ObXZ4X1JhbGx4X2RlbW9fTkVXLm9iaiIpCnNtYXAuNXNwW1snamNvZiddXQpgYGAKCiMjIyMgWzEwLjFdIENvbXBhcmUgc3RhbmRhcmQgUy1tYXAsIE1EUiBTLW1hcCwgSUlTLCBDSVMKQ1JJUyAoRXFuLjIxKSBhbmQgZGlyZWN0X0lTIChFcW4uMTkpCmBgYHtyfQojbm9ybWFsaXphdGlvbiBieSBTRApzZF9hZGpfMzUgPC0gYXMubnVtZXJpYyhyazRfcmVzdWx0LnNkWzVdIC8gcms0X3Jlc3VsdC5zZFszXSkKCkNSSVNfZEMxZEMxIDwtIHByZWNpc2VfY29lZmZfNXNwW1sxXV1bMywzXSAtIDEuMApkaXJlY3RfZEMxZEMxIDwtIGRpcmVjdF9jb2VmZl81c3BbWzFdXVszLDNdIC0gMS4wCkNSSVNfZEMxZFIgPC0gc2RfYWRqXzM1ICogcHJlY2lzZV9jb2VmZl81c3BbWzFdXVszLDVdCmRpcmVjdF9kQzFkUiA8LSBzZF9hZGpfMzUgKiBkaXJlY3RfY29lZmZfNXNwW1sxXV1bMyw1XQpmb3IoaiBpbiAyOjIwMCkgewogIENSSVNfZEMxZEMxIDwtIGFwcGVuZChDUklTX2RDMWRDMSwgcHJlY2lzZV9jb2VmZl81c3BbW2pdXVszLDNdIC0gMS4wKQogIGRpcmVjdF9kQzFkQzEgPC0gYXBwZW5kKGRpcmVjdF9kQzFkQzEsIGRpcmVjdF9jb2VmZl81c3BbW2pdXVszLDNdIC0gMS4wKQogIENSSVNfZEMxZFIgPC0gYXBwZW5kKENSSVNfZEMxZFIsIHNkX2Fkal8zNSAqIHByZWNpc2VfY29lZmZfNXNwW1tqXV1bMyw1XSkKICBkaXJlY3RfZEMxZFIgPC0gYXBwZW5kKGRpcmVjdF9kQzFkUiwgc2RfYWRqXzM1ICogZGlyZWN0X2NvZWZmXzVzcFtbal1dWzMsNV0pCn0KYGBgCgoKRGF0YWZyYW1lIGZvciBiYXNpYyBwbG90CmBgYHtyfQpmaW5hbF9JRCA8LSAyMDEKdGF1IDwtIDUuMApmb29kX2NoYWluX3Jlc3VsdCA8LSBkYXRhLmZyYW1lKHRpbWUgPSByazRfcmVzdWx0JHRbLWZpbmFsX0lEXSwgc3RkX3NtYXBDMXRvQzEgPSByazRfbV9zbWFwX3JlczJfcyRzbWFwX2NvZWZmaWNpZW50c1tbMV1dJGNfM1stZmluYWxfSURdIC0gMS4wLCBzdGRfc21hcFJ0b0MxID0gcms0X21fc21hcF9yZXMyX3Mkc21hcF9jb2VmZmljaWVudHNbWzFdXSRjXzVbLWZpbmFsX0lEXSwgbWRyX3NtYXBDMXRvQzEgPSBzdWJzZXQoc21hcC41c3BbWydqY29mJ11dLCB2YXJpYWJsZSA9PSBqX0MxKVsxOjIwMCwgN10gLSAxLjAsIG1kcl9zbWFwUnRvQzEgPSBzdWJzZXQoc21hcC41c3BbWydqY29mJ11dLCB2YXJpYWJsZSA9PSBqX0MxKVsxOjIwMCwgOV0sIElJU19kQzFkQzEgPSB0YXUqZEMxZEMxKHJrNF9yZXN1bHQpWy1maW5hbF9JRF0sIElJU19kQzFkUiA9IHRhdSpkQzFkUihyazRfcmVzdWx0KVstZmluYWxfSURdLCBDUklTX2RDMWRDMSwgQ1JJU19kQzFkUiwgZGlyZWN0X2RDMWRDMSwgZGlyZWN0X2RDMWRSKQoKZm9vZF9jaGFpbl9yZXN1bHQKYGBgCgpEYXRhZnJhbWUgZm9yIGdncGxvdApgYGB7cn0KI0ZvciBsaW5lcGxvdHMKcms0X0MxdG9DMV9nZ3Bsb3QgPC0gZGF0YS5mcmFtZSgKICB0aW1lID0gZm9vZF9jaGFpbl9yZXN1bHQkdGltZSwKICBJbnRTID0gZm9vZF9jaGFpbl9yZXN1bHQkc3RkX3NtYXBDMXRvQzEsCiAgdHlwZSA9IHJlcCgiMDFzdGRfc21hcEMxdG9DMSIsIDIwMCkKKQpyazRfQzF0b0MxX2dncGxvdCA8LSByYmluZC5kYXRhLmZyYW1lKAogIHJrNF9DMXRvQzFfZ2dwbG90LCBkYXRhLmZyYW1lKAogICAgdGltZSA9IGZvb2RfY2hhaW5fcmVzdWx0JHRpbWUsCiAgICBJbnRTID0gZm9vZF9jaGFpbl9yZXN1bHQkbWRyX3NtYXBDMXRvQzEsCiAgICB0eXBlID0gcmVwKCIwMm1kcl9zbWFwQzF0b0MxIiwgMjAwKQogICkKKQpyazRfQzF0b0MxX2dncGxvdCA8LSByYmluZC5kYXRhLmZyYW1lKAogIHJrNF9DMXRvQzFfZ2dwbG90LCBkYXRhLmZyYW1lKAogICAgdGltZSA9IGZvb2RfY2hhaW5fcmVzdWx0JHRpbWUsCiAgICBJbnRTID0gZm9vZF9jaGFpbl9yZXN1bHQkQ1JJU19kQzFkQzEsCiAgICB0eXBlID0gcmVwKCIwM0NSSVNfZEMxZEMxIiwgMjAwKQogICkKKQpyazRfQzF0b0MxX2dncGxvdCA8LSByYmluZC5kYXRhLmZyYW1lKAogIHJrNF9DMXRvQzFfZ2dwbG90LCBkYXRhLmZyYW1lKAogICAgdGltZSA9IGZvb2RfY2hhaW5fcmVzdWx0JHRpbWUsCiAgICBJbnRTID0gZm9vZF9jaGFpbl9yZXN1bHQkSUlTX2RDMWRDMSwKICAgIHR5cGUgPSByZXAoIjA0SUlTX2RDMWRDMSIsIDIwMCkKICApCikgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgCgpyazRfUnRvQzFfZ2dwbG90IDwtIGRhdGEuZnJhbWUoCiAgdGltZSA9IGZvb2RfY2hhaW5fcmVzdWx0JHRpbWUsCiAgSW50UyA9IGZvb2RfY2hhaW5fcmVzdWx0JHN0ZF9zbWFwUnRvQzEsCiAgdHlwZSA9IHJlcCgiMDFzdGRfc21hcFJ0b0MxIiwgMjAwKQopCnJrNF9SdG9DMV9nZ3Bsb3QgPC0gcmJpbmQuZGF0YS5mcmFtZSgKICByazRfUnRvQzFfZ2dwbG90LCBkYXRhLmZyYW1lKAogICAgdGltZSA9IGZvb2RfY2hhaW5fcmVzdWx0JHRpbWUsCiAgICBJbnRTID0gZm9vZF9jaGFpbl9yZXN1bHQkbWRyX3NtYXBSdG9DMSwKICAgIHR5cGUgPSByZXAoIjAybWRyX3NtYXBSdG9DMSIsIDIwMCkKICApCikKcms0X1J0b0MxX2dncGxvdCA8LSByYmluZC5kYXRhLmZyYW1lKAogIHJrNF9SdG9DMV9nZ3Bsb3QsIGRhdGEuZnJhbWUoCiAgICB0aW1lID0gZm9vZF9jaGFpbl9yZXN1bHQkdGltZSwKICAgIEludFMgPSBmb29kX2NoYWluX3Jlc3VsdCRDUklTX2RDMWRSLAogICAgdHlwZSA9IHJlcCgiMDNDUklTX2RDMWRSIiwgMjAwKQogICkKKQpyazRfUnRvQzFfZ2dwbG90IDwtIHJiaW5kLmRhdGEuZnJhbWUoCiAgcms0X1J0b0MxX2dncGxvdCwgZGF0YS5mcmFtZSgKICAgIHRpbWUgPSBmb29kX2NoYWluX3Jlc3VsdCR0aW1lLAogICAgSW50UyA9IGZvb2RfY2hhaW5fcmVzdWx0JElJU19kQzFkUiwKICAgIHR5cGUgPSByZXAoIjA0SUlTX2RDMWRSIiwgMjAwKQogICkKKQoKI0ZvciBlcnJvciBwbG90cwpyazRfZXJyb3JfQzF0b0MxX2dncGxvdCA8LSBkYXRhLmZyYW1lKAogIHRpbWUgPSBmb29kX2NoYWluX3Jlc3VsdCR0aW1lLAogIEludFMgPSBmb29kX2NoYWluX3Jlc3VsdCRzdGRfc21hcEMxdG9DMSAtIGZvb2RfY2hhaW5fcmVzdWx0JGRpcmVjdF9kQzFkQzEsCiAgdHlwZSA9IHJlcCgiMDFzdGRfc21hcEMxdG9DMSIsIDIwMCkKKQpyazRfZXJyb3JfQzF0b0MxX2dncGxvdCA8LSByYmluZC5kYXRhLmZyYW1lKAogIHJrNF9lcnJvcl9DMXRvQzFfZ2dwbG90LCBkYXRhLmZyYW1lKAogICAgdGltZSA9IGZvb2RfY2hhaW5fcmVzdWx0JHRpbWUsCiAgICBJbnRTID0gZm9vZF9jaGFpbl9yZXN1bHQkbWRyX3NtYXBDMXRvQzEgLSBmb29kX2NoYWluX3Jlc3VsdCRkaXJlY3RfZEMxZEMxLAogICAgdHlwZSA9IHJlcCgiMDJtZHJfc21hcEMxdG9DMSIsIDIwMCkKICApCikKcms0X2Vycm9yX0MxdG9DMV9nZ3Bsb3QgPC0gcmJpbmQuZGF0YS5mcmFtZSgKICByazRfZXJyb3JfQzF0b0MxX2dncGxvdCwgZGF0YS5mcmFtZSgKICAgIHRpbWUgPSBmb29kX2NoYWluX3Jlc3VsdCR0aW1lLAogICAgSW50UyA9IGZvb2RfY2hhaW5fcmVzdWx0JENSSVNfZEMxZEMxIC0gZm9vZF9jaGFpbl9yZXN1bHQkZGlyZWN0X2RDMWRDMSwKICAgIHR5cGUgPSByZXAoIjAzQ1JJU19kQzFkQzEiLCAyMDApCiAgKQopCnJrNF9lcnJvcl9DMXRvQzFfZ2dwbG90IDwtIHJiaW5kLmRhdGEuZnJhbWUoCiAgcms0X2Vycm9yX0MxdG9DMV9nZ3Bsb3QsIGRhdGEuZnJhbWUoCiAgICB0aW1lID0gZm9vZF9jaGFpbl9yZXN1bHQkdGltZSwKICAgIEludFMgPSBmb29kX2NoYWluX3Jlc3VsdCRJSVNfZEMxZEMxIC0gZm9vZF9jaGFpbl9yZXN1bHQkZGlyZWN0X2RDMWRDMSwKICAgIHR5cGUgPSByZXAoIjA0SUlTX2RDMWRDMSIsIDIwMCkKICApCikKCnJrNF9lcnJvcl9SdG9DMV9nZ3Bsb3QgPC0gZGF0YS5mcmFtZSgKICB0aW1lID0gZm9vZF9jaGFpbl9yZXN1bHQkdGltZSwKICBJbnRTID0gZm9vZF9jaGFpbl9yZXN1bHQkc3RkX3NtYXBSdG9DMSAtIGZvb2RfY2hhaW5fcmVzdWx0JGRpcmVjdF9kQzFkUiwKICB0eXBlID0gcmVwKCIwMXN0ZF9zbWFwUnRvQzEiLCAyMDApCikKcms0X2Vycm9yX1J0b0MxX2dncGxvdCA8LSByYmluZC5kYXRhLmZyYW1lKAogIHJrNF9lcnJvcl9SdG9DMV9nZ3Bsb3QsIGRhdGEuZnJhbWUoCiAgICB0aW1lID0gZm9vZF9jaGFpbl9yZXN1bHQkdGltZSwKICAgIEludFMgPSBmb29kX2NoYWluX3Jlc3VsdCRtZHJfc21hcFJ0b0MxIC0gZm9vZF9jaGFpbl9yZXN1bHQkZGlyZWN0X2RDMWRSLAogICAgdHlwZSA9IHJlcCgiMDJtZHJfc21hcFJ0b0MxIiwgMjAwKQogICkKKQpyazRfZXJyb3JfUnRvQzFfZ2dwbG90IDwtIHJiaW5kLmRhdGEuZnJhbWUoCiAgcms0X2Vycm9yX1J0b0MxX2dncGxvdCwgZGF0YS5mcmFtZSgKICAgIHRpbWUgPSBmb29kX2NoYWluX3Jlc3VsdCR0aW1lLAogICAgSW50UyA9IGZvb2RfY2hhaW5fcmVzdWx0JENSSVNfZEMxZFIgLSBmb29kX2NoYWluX3Jlc3VsdCRkaXJlY3RfZEMxZFIsCiAgICB0eXBlID0gcmVwKCIwM0NSSVNfZEMxZFIiLCAyMDApCiAgKQopCnJrNF9lcnJvcl9SdG9DMV9nZ3Bsb3QgPC0gcmJpbmQuZGF0YS5mcmFtZSgKICByazRfZXJyb3JfUnRvQzFfZ2dwbG90LCBkYXRhLmZyYW1lKAogICAgdGltZSA9IGZvb2RfY2hhaW5fcmVzdWx0JHRpbWUsCiAgICBJbnRTID0gZm9vZF9jaGFpbl9yZXN1bHQkSUlTX2RDMWRSIC0gZm9vZF9jaGFpbl9yZXN1bHQkZGlyZWN0X2RDMWRSLAogICAgdHlwZSA9IHJlcCgiMDRJSVNfZEMxZFIiLCAyMDApCiAgKQopCgoKYGBgCgojIyMjIyBbMTAuMS4xXSBDb21wYXJpc29uIGZvciB0aGUgZGlhZ29uYWwgZWxlbWVudCAoRmlnLiAzYTogQzEgLT4gQzEpOiBiYXNpYyBwbG90CmBgYHtyfQpwbG90KGZvb2RfY2hhaW5fcmVzdWx0JHRpbWUsIGZvb2RfY2hhaW5fcmVzdWx0JENSSVNfZEMxZEMxLCB0eXBlID0gImwiLCBjb2wgPSAiI2Y2YWEwMCIsIHhsaW0gPSBjKDE0MDAsIDE4MDApLCB5bGltID0gYygtMywgMi4wKSwgeGxhYiA9ICJ0aW1lIiwgeWxhYiA9ICJTbWFwIGNvZWZmaWNpZW50OiBDMSAtPiBDMSIpCnBhcihuZXcgPSBUKQpwbG90KGZvb2RfY2hhaW5fcmVzdWx0JHRpbWUsIGZvb2RfY2hhaW5fcmVzdWx0JHN0ZF9zbWFwQzF0b0MxLCB0eXBlID0gImwiLCBjb2wgPSAiI2ZmNGIwMCIsIHhsaW0gPSBjKDE0MDAsIDE4MDApLCB5bGltID0gYygtMywgMi4wKSwgeGxhYiA9ICIiLCB5bGFiID0gIiIpCnBhcihuZXcgPSBUKQpwbG90KGZvb2RfY2hhaW5fcmVzdWx0JHRpbWUsIGZvb2RfY2hhaW5fcmVzdWx0JG1kcl9zbWFwQzF0b0MxLCB0eXBlID0gImwiLCBjb2wgPSAiIzRkYzRmZiIsIHhsaW0gPSBjKDE0MDAsIDE4MDApLCB5bGltID0gYygtMywgMi4wKSwgeGxhYiA9ICIiLCB5bGFiID0gIiIpCnBhcihuZXcgPSBUKQpwbG90KGZvb2RfY2hhaW5fcmVzdWx0JHRpbWUsIGZvb2RfY2hhaW5fcmVzdWx0JElJU19kQzFkQzEsIHR5cGUgPSAibCIsIGx0eSA9ICJkYXNoZWQiLCBjb2wgPSAiIzgwNDAwMCIsIHhsaW0gPSBjKDE0MDAsIDE4MDApLCB5bGltID0gYygtMywgMi4wKSwgeGxhYiA9ICIiLCB5bGFiID0gIiIpCmBgYAojIyMjIyBbMTAuMS4yXSBDb21wYXJpc29uIGZvciB0aGUgZGlhZ29uYWwgZWxlbWVudCAoRmlnLiAzYWI6IEMxIC0+IEMxKTogZ2dwbG90CgpgYGB7ciB3YXJuaW5nID0gRkFMU0V9CmZpZzNhX2dncGxvdCA8LSBnZ3Bsb3QoZGF0YSA9IHJrNF9DMXRvQzFfZ2dwbG90KSArCiAgc2NhbGVfY29sb3VyX21hbnVhbCh2YWx1ZXMgPSBjKCIjZmY0YjAwIiwgIiM0ZGM0ZmYiLCAiI2Y2YWEwMCIsICIjODA0MDAwIikpICsKICBzY2FsZV9zaGFwZV9tYW51YWwodmFsdWVzID0gYygxNSwgMTYsIDE3LCA1KSkgKwrjgIBnZW9tX2xpbmUoYWVzKHggPSB0aW1lLCB5ID0gSW50UywgZ3JvdXAgPSB0eXBlLCBjb2xvciA9IHR5cGUpKSArCiAgZ2VvbV9wb2ludChhZXMoeCA9IHRpbWUsIHkgPSBJbnRTLCBjb2xvciA9IHR5cGUsIHNoYXBlID0gdHlwZSksIHNpemUgPSAyKSArCiAgeGxpbSgxNDAwLCAxODAwKSArIHRoZW1lX2J3KCkgKyB0aGVtZShsZWdlbmQucG9zaXRpb24gPSAiYm90dG9tIikgKwogIGxhYnModGl0bGUgPSAiVGltZSBldm9sdXRpb246IEMxIC0+IEMxIiwgeCA9ICJ0aW1lIiwgeSA9ICJDMSAtPiBDMSIpIAoKZmlnM2JfZ2dwbG90IDwtIGdncGxvdChyazRfZXJyb3JfQzF0b0MxX2dncGxvdCwgYWVzKHR5cGUsIGFicyhJbnRTKSkpICsKICAgIHNjYWxlX2NvbG91cl9tYW51YWwodmFsdWVzID0gYygiI2ZmNGIwMCIsICIjNGRjNGZmIiwgIiNmNmFhMDAiLCAiIzgwNDAwMCIpKSArCiAgICBzY2FsZV9zaGFwZV9tYW51YWwodmFsdWVzID0gYygxNSwgMTYsIDE3LCA1KSkgKwogICAgZ2VvbV9ib3hwbG90KG91dGxpZXIuc2hhcGUgPSBOQSkgKwogICAgZ2VvbV9qaXR0ZXIoYWVzKHNoYXBlID0gdHlwZSwgY29sb3IgPSB0eXBlLCBhbHBoYSA9IDAuMSksIHdpZHRoID0gMC4yNSwgc2l6ZSA9IDMpICsKICAgIHRoZW1lX2J3KCkgKyB0aGVtZShsZWdlbmQucG9zaXRpb24gPSAiYm90dG9tIikgKwogICAgbGFicyAodGl0bGUgPSAiQ29tcGFyaXNvbiB0byBkaXJlY3RfZXZhbHVhdGlvbjogQzEgLT4gQzEiKSAKCnBsb3QoZmlnM2FfZ2dwbG90KQpnZ3NhdmUoImZpZzNhLnBkZiIsIHdpZHRoID0gNiwgaGVpZ2h0ID0gNCkKcGxvdChmaWczYl9nZ3Bsb3QpCmdnc2F2ZSgiZmlnM2IucGRmIiwgd2lkdGggPSA0LCBoZWlnaHQgPSA0KQpgYGAKRGlmZmVyZW5jZSBiZXR3ZWVuIGRpcmVjdGx5LWV2YWx1YXRlZCBDSVMgYW5kIENJUyBieSBsaW5lYXJpemVkIE9ERQpgYGB7cn0Kc3VtbWFyeShhYnMoZm9vZF9jaGFpbl9yZXN1bHQkQ1JJU19kQzFkQzEgLSBmb29kX2NoYWluX3Jlc3VsdCRkaXJlY3RfZEMxZEMxKSkKYGBgCgoKIyMjIyMgWzEwLjEuM10gQ29tcGFyaXNvbiBmb3IgdGhlIGRpYWdvbmFsIGVsZW1lbnQgKEZpZy4gM2NkOiBSIC0+IEMxKTogZ2dwbG90CgpgYGB7ciB3YXJuaW5nID0gRkFMU0V9CmZpZzNjX2dncGxvdCA8LSBnZ3Bsb3QoZGF0YSA9IHJrNF9SdG9DMV9nZ3Bsb3QpICsKICBzY2FsZV9jb2xvdXJfbWFudWFsKHZhbHVlcyA9IGMoIiNmZjRiMDAiLCAiIzRkYzRmZiIsICIjZjZhYTAwIiwgIiM4MDQwMDAiKSkgKwogIHNjYWxlX3NoYXBlX21hbnVhbCh2YWx1ZXMgPSBjKDE1LCAxNiwgMTcsIDUpKSArCuOAgGdlb21fbGluZShhZXMoeCA9IHRpbWUsIHkgPSBJbnRTLCBncm91cCA9IHR5cGUsIGNvbG9yID0gdHlwZSkpICsKICBnZW9tX3BvaW50KGFlcyh4ID0gdGltZSwgeSA9IEludFMsIGNvbG9yID0gdHlwZSwgc2hhcGUgPSB0eXBlKSwgc2l6ZSA9IDIpICsKICB4bGltKDE0MDAsIDE4MDApICsgdGhlbWVfYncoKSArIHRoZW1lKGxlZ2VuZC5wb3NpdGlvbiA9ICJib3R0b20iKSArCiAgbGFicyh0aXRsZSA9ICJUaW1lIGV2b2x1dGlvbjogUiAtPiBDMSIsIHggPSAidGltZSIsIHkgPSAiUiAtPiBDMSIpIAoKZmlnM2RfZ2dwbG90IDwtIGdncGxvdChyazRfZXJyb3JfUnRvQzFfZ2dwbG90LCBhZXModHlwZSwgYWJzKEludFMpKSkgKwogICAgc2NhbGVfY29sb3VyX21hbnVhbCh2YWx1ZXMgPSBjKCIjZmY0YjAwIiwgIiM0ZGM0ZmYiLCAiI2Y2YWEwMCIsICIjODA0MDAwIikpICsKICAgIHNjYWxlX3NoYXBlX21hbnVhbCh2YWx1ZXMgPSBjKDE1LCAxNiwgMTcsIDUpKSArCiAgICBnZW9tX2JveHBsb3Qob3V0bGllci5zaGFwZSA9IE5BKSArCiAgICBnZW9tX2ppdHRlcihhZXMoc2hhcGUgPSB0eXBlLCBjb2xvciA9IHR5cGUsIGFscGhhID0gMC4xKSwgd2lkdGggPSAwLjI1LCBzaXplID0gMykgKwogICAgdGhlbWVfYncoKSArIHRoZW1lKGxlZ2VuZC5wb3NpdGlvbiA9ICJib3R0b20iKSArCiAgICBsYWJzICh0aXRsZSA9ICJDb21wYXJpc29uIHRvIGRpcmVjdF9ldmFsdWF0aW9uOiBSIC0+IEMxIikgCgpwbG90KGZpZzNjX2dncGxvdCkKZ2dzYXZlKCJmaWczYy5wZGYiLCB3aWR0aCA9IDYsIGhlaWdodCA9IDQpCnBsb3QoZmlnM2RfZ2dwbG90KQpnZ3NhdmUoImZpZzNkLnBkZiIsIHdpZHRoID0gNCwgaGVpZ2h0ID0gNCkKYGBgCkRpZmZlcmVuY2UgYmV0d2VlbiBkaXJlY3RseS1ldmFsdWF0ZWQgQ0lTIGFuZCBDSVMgYnkgbGluZWFyaXplZCBPREUKYGBge3J9CnN1bW1hcnkoYWJzKGZvb2RfY2hhaW5fcmVzdWx0JENSSVNfZEMxZFIgLSBmb29kX2NoYWluX3Jlc3VsdCRkaXJlY3RfZEMxZFIpKQpgYGAKCiMjIyMjIFsxMC4xLjRdIENvbXBhcmlzb24gZm9yIGJvdGggZGlhZ29uYWwgYW5kIG9mZi1kaWFnb25hbCBieSBjb3JyZWxhdGlvbi9yZWdyZXNzaW9uCmBgYHtyfQojZm9yIGRpYWdvbmFsIGVsZW1lbnQgKEMxIC0+IEMxKQpwbG90KGZvb2RfY2hhaW5fcmVzdWx0JHN0ZF9zbWFwQzF0b0MxIH4gZm9vZF9jaGFpbl9yZXN1bHQkZGlyZWN0X2RDMWRDMSwgCiAgICAgeGxhYiA9ICJkaXJlY3QgZXZhbHVhdGlvbiAoQzEgLT4gQzEpIiwKICAgICB5bGFiID0gInN0YW5kYXJkIFMtbWFwIGNvZWZmaWNpZW50IChDMSAtPiBDMSkiLAogICAgICkKYWJsaW5lKGNvZWYgPSBjKDAsMSkpCgpjb3IoZm9vZF9jaGFpbl9yZXN1bHQkc3RkX3NtYXBDMXRvQzFbLTIwMF0sIGZvb2RfY2hhaW5fcmVzdWx0JGRpcmVjdF9kQzFkQzFbLTIwMF0pCiNZIHNob3VsZCBiZSB0aGUgdGhlb3JldGljYWwgY29lZmZpY2llbnQKc3VtbWFyeShsbShmb29kX2NoYWluX3Jlc3VsdCRkaXJlY3RfZEMxZEMxWy0yMDBdIH4gZm9vZF9jaGFpbl9yZXN1bHQkc3RkX3NtYXBDMXRvQzFbLTIwMF0pKQoKcGxvdChmb29kX2NoYWluX3Jlc3VsdCRtZHJfc21hcEMxdG9DMSB+IGZvb2RfY2hhaW5fcmVzdWx0JGRpcmVjdF9kQzFkQzEsIAogICAgIHhsYWIgPSAiZGlyZWN0IGV2YWx1YXRpb24gKEMxIC0+IEMxKSIsCiAgICAgeWxhYiA9ICJNRFIgUy1tYXAgY29lZmZpY2llbnQgKEMxIC0+IEMxKSIsCiAgICAgKQphYmxpbmUoY29lZiA9IGMoMCwxKSkKCmNvcihmb29kX2NoYWluX3Jlc3VsdCRtZHJfc21hcEMxdG9DMVstMjAwXSwgZm9vZF9jaGFpbl9yZXN1bHQkZGlyZWN0X2RDMWRDMVstMjAwXSkKI1kgc2hvdWxkIGJlIHRoZSB0aGVvcmV0aWNhbCBjb2VmZmljaWVudApzdW1tYXJ5KGxtKGZvb2RfY2hhaW5fcmVzdWx0JGRpcmVjdF9kQzFkQzFbLTIwMF0gfiBmb29kX2NoYWluX3Jlc3VsdCRtZHJfc21hcEMxdG9DMVstMjAwXSkpCgpwbG90KGZvb2RfY2hhaW5fcmVzdWx0JElJU19kQzFkQzEgfiBmb29kX2NoYWluX3Jlc3VsdCRkaXJlY3RfZEMxZEMxLCAKICAgICB4bGFiID0gImRpcmVjdCBldmFsdWF0aW9uIChDMSAtPiBDMSkiLAogICAgIHlsYWIgPSAiaW5zdGFudGFuZW91cyBpbnRlcmFjdGlvbiBzdHJlbmd0aCAoQzEgLT4gQzEpIiwKICAgICApCmFibGluZShjb2VmID0gYygwLDEpKQoKY29yKGZvb2RfY2hhaW5fcmVzdWx0JElJU19kQzFkQzFbLTIwMF0sIGZvb2RfY2hhaW5fcmVzdWx0JGRpcmVjdF9kQzFkQzFbLTIwMF0pCiNZIHNob3VsZCBiZSB0aGUgdGhlb3JldGljYWwgY29lZmZpY2llbnQKc3VtbWFyeShsbShmb29kX2NoYWluX3Jlc3VsdCRkaXJlY3RfZEMxZEMxWy0yMDBdIH4gZm9vZF9jaGFpbl9yZXN1bHQkSUlTX2RDMWRDMVstMjAwXSkpCgoKI2ZvciBvZmYtZGlhZ29uYWwgZWxlbWVudCAoUiAtPiBDMSkKcGxvdChmb29kX2NoYWluX3Jlc3VsdCRzdGRfc21hcFJ0b0MxIH4gZm9vZF9jaGFpbl9yZXN1bHQkZGlyZWN0X2RDMWRSLCAKICAgICB4bGFiID0gImRpcmVjdCBldmFsdWF0aW9uIChSIC0+IEMxKSIsCiAgICAgeWxhYiA9ICJzdGFuZGFyZCBTLW1hcCBjb2VmZmljaWVudCAoUiAtPiBDMSkiLAogICAgICkKYWJsaW5lKGNvZWYgPSBjKDAsMSkpCgpjb3IoZm9vZF9jaGFpbl9yZXN1bHQkc3RkX3NtYXBSdG9DMVstMjAwXSwgZm9vZF9jaGFpbl9yZXN1bHQkZGlyZWN0X2RDMWRSWy0yMDBdKQojWSBzaG91bGQgYmUgdGhlIHRoZW9yZXRpY2FsIGNvZWZmaWNpZW50CnN1bW1hcnkobG0oZm9vZF9jaGFpbl9yZXN1bHQkZGlyZWN0X2RDMWRSWy0yMDBdIH4gZm9vZF9jaGFpbl9yZXN1bHQkc3RkX3NtYXBSdG9DMVstMjAwXSkpCgpwbG90KGZvb2RfY2hhaW5fcmVzdWx0JG1kcl9zbWFwUnRvQzEgfiBmb29kX2NoYWluX3Jlc3VsdCRkaXJlY3RfZEMxZFIsIAogICAgIHhsYWIgPSAiZGlyZWN0IGV2YWx1YXRpb24gKFIgLT4gQzEpIiwKICAgICB5bGFiID0gIk1EUiBTLW1hcCBjb2VmZmljaWVudCAoUiAtPiBDMSkiLAogICAgICkKYWJsaW5lKGNvZWYgPSBjKDAsMSkpCgpjb3IoZm9vZF9jaGFpbl9yZXN1bHQkbWRyX3NtYXBSdG9DMVstMjAwXSwgZm9vZF9jaGFpbl9yZXN1bHQkZGlyZWN0X2RDMWRSWy0yMDBdKQojWSBzaG91bGQgYmUgdGhlIHRoZW9yZXRpY2FsIGNvZWZmaWNpZW50CnN1bW1hcnkobG0oZm9vZF9jaGFpbl9yZXN1bHQkZGlyZWN0X2RDMWRSWy0yMDBdIH4gZm9vZF9jaGFpbl9yZXN1bHQkbWRyX3NtYXBSdG9DMVstMjAwXSkpCgpwbG90KGZvb2RfY2hhaW5fcmVzdWx0JElJU19kQzFkUiB+IGZvb2RfY2hhaW5fcmVzdWx0JGRpcmVjdF9kQzFkUiwgCiAgICAgeGxhYiA9ICJkaXJlY3QgZXZhbHVhdGlvbiAoUiAtPiBDMSkiLAogICAgIHlsYWIgPSAiaW5zdGFudGFuZW91cyBpbnRlcmFjdGlvbiBzdHJlbmd0aCAoUiAtPiBDMSkiLAogICAgICkKYWJsaW5lKGNvZWYgPSBjKDAsMSkpCgpjb3IoZm9vZF9jaGFpbl9yZXN1bHQkSUlTX2RDMWRSWy0yMDBdLCBmb29kX2NoYWluX3Jlc3VsdCRkaXJlY3RfZEMxZFJbLTIwMF0pCiNZIHNob3VsZCBiZSB0aGUgdGhlb3JldGljYWwgY29lZmZpY2llbnQKc3VtbWFyeShsbShmb29kX2NoYWluX3Jlc3VsdCRkaXJlY3RfZEMxZFJbLTIwMF0gfiBmb29kX2NoYWluX3Jlc3VsdCRJSVNfZEMxZFJbLTIwMF0pKQoKYGBgCgoKIyMjIyBbMTAuMl0gQ29tcGFyZSBJbnN0YW50YW5lb3VzIEphY29iaWFuIGFuZCBDSVMKCk5vdGUgdGhhdDogCgoxKSBQcmVjaXNlIGNvZWZmIHdpdGggdmVyeSBzaG9ydCBpbnRlcnZhbCAoZGVsdGF0ID0gMC4wMSkgaXMgaWRlbnRpY2FsIHRvIGluc3RhbnRhbmVvdXMgSmFjb2JpYW4KCiMjIyMjIFsxMC4yLjFdIEZvciBlYWNoIGdyYXBoIGluZGVwZW5kZW50bHkgCmBgYHtyfQpkZWx0YV8zMyA8LSAxIApwcmVjaXNlX2RhdGEgPC0gZGF0YS5mcmFtZSh0ID0gcms0X3Jlc3VsdCR0WzFdLCBwcmVjaXNlX2RDMWRDMSA9IHByZWNpc2VfY29lZmZfNXNwW1sxXV1bMywzXSAtIGRlbHRhXzMzLCBpbnN0X3ByZWNpc2VfZEMxZEMxID0gaW5zdF9wcmVjaXNlX2NvZWZmXzVzcFtbMV1dWzMsM10gLSBkZWx0YV8zMywgdGF1MC41X3ByZWNpc2VfZEMxZEMxID0gdGF1MC41X3ByZWNpc2VfY29lZmZfNXNwW1sxXV1bMywzXSAtIGRlbHRhXzMzLCB0YXUxLjBfcHJlY2lzZV9kQzFkQzEgPSB0YXUxLjBfcHJlY2lzZV9jb2VmZl81c3BbWzFdXVszLDNdIC0gZGVsdGFfMzMsIHRhdTIuMF9wcmVjaXNlX2RDMWRDMSA9IHRhdTIuMF9wcmVjaXNlX2NvZWZmXzVzcFtbMV1dWzMsM10gLSBkZWx0YV8zMywgdGF1MTAuMF9wcmVjaXNlX2RDMWRDMSA9IHRhdTEwLjBfcHJlY2lzZV9jb2VmZl81c3BbWzFdXVszLDNdIC0gZGVsdGFfMzMpCmZvcihqIGluIDI6MjAwKSBwcmVjaXNlX2RhdGEgPC0gcmJpbmQuZGF0YS5mcmFtZShwcmVjaXNlX2RhdGEsIGMocms0X3Jlc3VsdCR0W2pdLCBwcmVjaXNlX2NvZWZmXzVzcFtbal1dWzMsM10gLSBkZWx0YV8zMywgaW5zdF9wcmVjaXNlX2NvZWZmXzVzcFtbal1dWzMsM10gLSBkZWx0YV8zMywgdGF1MC41X3ByZWNpc2VfY29lZmZfNXNwW1tqXV1bMywzXSAtIGRlbHRhXzMzLCB0YXUxLjBfcHJlY2lzZV9jb2VmZl81c3BbW2pdXVszLDNdIC0gZGVsdGFfMzMsIHRhdTIuMF9wcmVjaXNlX2NvZWZmXzVzcFtbal1dWzMsM10gLSBkZWx0YV8zMywgdGF1MTAuMF9wcmVjaXNlX2NvZWZmXzVzcFtbal1dWzMsM10gLSBkZWx0YV8zMykpCgpwbG90KHJrNF9yZXN1bHQkdFsxMDE6MTgxXSwgdGF1MipkQzFkQzEocms0X3Jlc3VsdClbMTAxOjE4MV0sIHR5cGUgPSAibCIsIGNvbCA9ICJibGFjayIsIHlsaW0gPSBjKC0wLjAwNSwgMC4wMDUpLCB4bGFiID0gInRpbWUiLCB5bGFiID0gIkludGVyYWN0aW9uIHN0cmVuZ3RocyBDMSAtPiBDMSIsIGx3ZCA9IDEsIG1haW4gPSBleHByZXNzaW9uKHBhc3RlKHRhdSwgIj0gMC4wMSIsIHNlcD0iIikpKQpwYXIobmV3ID0gVCkKcGxvdChyazRfcmVzdWx0JHRbMTAxOjE4MV0sIHByZWNpc2VfZGF0YSRpbnN0X3ByZWNpc2VfZEMxZEMxWzEwMToxODFdLCB0eXBlID0gImwiLCBjb2wgPSAiI2ZmNGIwMCIsIGx3ZCA9IDIsIGx0eSA9IDIsIHlsaW0gPSBjKC0wLjAwNSwgMC4wMDUpLCB4bGFiID0gIiIsIHlsYWIgPSAiIikKCmxlZ2VuZCgiYm90dG9tcmlnaHQiLCAKICAgICAgICAgIGxlZ2VuZCA9IGMoImluc3RhbnRhbmVvdXMgaW50ZXJhY3Rpb24gc3RyZW5ndGgiLCAiY3VtdWxhdGl2ZSBpbnRlcmFjdGlvbiBzdHJlbmd0aCIpLCAgCiAgICAgICAgICBjb2wgPSBjKCJibGFjayIsICIjZmY0YjAwIiksIAogICAgICAgICAgbHR5ID0gYygxLCAyKSwgICAgICAgICAgICAgIAogICAgICAgICAgY2V4ID0gYygwLjgpCikKCnBsb3Qocms0X3Jlc3VsdCR0WzEwMToxODFdLCB0YXUzKmRDMWRDMShyazRfcmVzdWx0KVsxMDE6MTgxXSwgdHlwZSA9ICJsIiwgY29sID0gImJsYWNrIiwgeWxpbSA9IGMoLTAuNCwgMC4zKSwgeGxhYiA9ICJ0aW1lIiwgeWxhYiA9ICJJbnRlcmFjdGlvbiBzdHJlbmd0aHMgQzEgLT4gQzEiLCBsd2QgPSAxLCBtYWluID0gZXhwcmVzc2lvbihwYXN0ZSh0YXUsICI9IDAuNSIsIHNlcD0iIikpKQpwYXIobmV3ID0gVCkKcGxvdChyazRfcmVzdWx0JHRbMTAxOjE4MV0sIHByZWNpc2VfZGF0YSR0YXUwLjVfcHJlY2lzZV9kQzFkQzFbMTAxOjE4MV0sIHR5cGUgPSAibCIsIGNvbCA9ICIjZmY0YjAwIiwgbHdkID0gMiwgbHR5ID0gMiwgeWxpbSA9IGMoLTAuNCwgMC4zKSwgeGxhYiA9ICIiLCB5bGFiID0gIiIpCgoKCnBsb3Qocms0X3Jlc3VsdCR0WzEwMToxODFdLCB0YXU0KmRDMWRDMShyazRfcmVzdWx0KVsxMDE6MTgxXSwgdHlwZSA9ICJsIiwgY29sID0gImJsYWNrIiwgeWxpbSA9IGMoMC4wLCAwLjE1KSwgeGxhYiA9ICJ0aW1lIiwgeWxhYiA9ICJJbnRlcmFjdGlvbiBzdHJlbmd0aHMgQzEgLT4gQzEiLCBsd2QgPSAxLCBtYWluID0gZXhwcmVzc2lvbihwYXN0ZSh0YXUsICI9IDEuMCIsIHNlcD0iIikpKQpwYXIobmV3ID0gVCkKcGxvdChyazRfcmVzdWx0JHRbMTAxOjE4MV0sIHByZWNpc2VfZGF0YSR0YXUxLjBfcHJlY2lzZV9kQzFkQzFbMTAxOjE4MV0sIHR5cGUgPSAibCIsIGNvbCA9ICIjZmY0YjAwIiwgbHdkID0gMiwgbHR5ID0gMiwgeWxpbSA9IGMoMC4wLCAwLjE1KSwgeGxhYiA9ICIiLCB5bGFiID0gIiIpCgoKcGxvdChyazRfcmVzdWx0JHRbMTAxOjE4MV0sIHRhdTUqZEMxZEMxKHJrNF9yZXN1bHQpWzEwMToxODFdLCB0eXBlID0gImwiLCBjb2wgPSAiYmxhY2siLCB5bGltID0gYygtMC40LCAwLjMpLCB4bGFiID0gInRpbWUiLCB5bGFiID0gIkludGVyYWN0aW9uIHN0cmVuZ3RocyBDMSAtPiBDMSIsIGx3ZCA9IDEsIG1haW4gPSBleHByZXNzaW9uKHBhc3RlKHRhdSwgIj0gMi4wIiwgc2VwPSIiKSkpCnBhcihuZXcgPSBUKQpwbG90KHJrNF9yZXN1bHQkdFsxMDE6MTgxXSwgcHJlY2lzZV9kYXRhJHRhdTIuMF9wcmVjaXNlX2RDMWRDMVsxMDE6MTgxXSwgdHlwZSA9ICJsIiwgY29sID0gIiNmZjRiMDAiLCBsd2QgPSAyLCBsdHkgPSAyLCB5bGltID0gYygtMC40LCAwLjMpLCB4bGFiID0gIiIsIHlsYWIgPSAiIikKCgpwbG90KHJrNF9yZXN1bHQkdFsxMDE6MTgxXSwgdGF1MSpkQzFkQzEocms0X3Jlc3VsdClbMTAxOjE4MV0sIHR5cGUgPSAibCIsIGNvbCA9ICJibGFjayIsIHlsaW0gPSBjKC0yLCAyKSwgeGxhYiA9ICJ0aW1lIiwgeWxhYiA9ICJJbnRlcmFjdGlvbiBzdHJlbmd0aHMgQzEgLT4gQzEiLCBsd2QgPSAxLCBtYWluID0gZXhwcmVzc2lvbihwYXN0ZSh0YXUsICI9IDUuMCIsIHNlcD0iIikpKQpwYXIobmV3ID0gVCkKcGxvdChyazRfcmVzdWx0JHRbMTAxOjE4MV0sIHByZWNpc2VfZGF0YSRwcmVjaXNlX2RDMWRDMVsxMDE6MTgxXSwgdHlwZSA9ICJsIiwgY29sID0gIiNmZjRiMDAiLCBsd2QgPSAyLCBsdHkgPSAyLCB5bGltID0gYygtMiwgMiksIHhsYWIgPSAiIiwgeWxhYiA9ICIiKQoKCnBsb3Qocms0X3Jlc3VsdCR0WzEwMToxODFdLCB0YXU2KmRDMWRDMShyazRfcmVzdWx0KVsxMDE6MTgxXSwgdHlwZSA9ICJsIiwgY29sID0gImJsYWNrIiwgeWxpbSA9IGMoLTIsIDMpLCB4bGFiID0gInRpbWUiLCB5bGFiID0gIkludGVyYWN0aW9uIHN0cmVuZ3RocyBDMSAtPiBDMSIsIGx3ZCA9IDEsIG1haW4gPSBleHByZXNzaW9uKHBhc3RlKHRhdSwgIj0gMTAuMCIsIHNlcD0iIikpKQpwYXIobmV3ID0gVCkKcGxvdChyazRfcmVzdWx0JHRbMTAxOjE4MV0sIHByZWNpc2VfZGF0YSR0YXUxMC4wX3ByZWNpc2VfZEMxZEMxWzEwMToxODFdLCB0eXBlID0gImwiLCBjb2wgPSAiI2ZmNGIwMCIsIGx3ZCA9IDIsIGx0eSA9IDIsIHlsaW0gPSBjKC0yLCAzKSwgeGxhYiA9ICIiLCB5bGFiID0gIiIpCgpgYGAKIyMjIyMgWzEwLjIuMl0gRm9yIGVhY2ggZ3JhcGggYXMgcGRmIGZvciBmaWd1cmUgNApgYGB7cn0KcGRmKCJmaWc0YS5wZGYiLCB3aWR0aCA9IDQsIGhlaWdodCA9IDQpCnBsb3Qocms0X3Jlc3VsdCR0WzEwMToxODFdLCB0YXUyKmRDMWRDMShyazRfcmVzdWx0KVsxMDE6MTgxXSwgdHlwZSA9ICJsIiwgY29sID0gImJsYWNrIiwgeWxpbSA9IGMoLTAuMDA1LCAwLjAwNSksIHhsYWIgPSAidGltZSIsIHlsYWIgPSAiSW50ZXJhY3Rpb24gc3RyZW5ndGhzIEMxIC0+IEMxIiwgbHdkID0gMSwgbWFpbiA9IGV4cHJlc3Npb24ocGFzdGUodGF1LCAiPSAwLjAxIiwgc2VwPSIiKSkpCnBhcihuZXcgPSBUKQpwbG90KHJrNF9yZXN1bHQkdFsxMDE6MTgxXSwgcHJlY2lzZV9kYXRhJGluc3RfcHJlY2lzZV9kQzFkQzFbMTAxOjE4MV0sIHR5cGUgPSAibCIsIGNvbCA9ICIjZmY0YjAwIiwgbHdkID0gMiwgbHR5ID0gMiwgeWxpbSA9IGMoLTAuMDA1LCAwLjAwNSksIHhsYWIgPSAiIiwgeWxhYiA9ICIiKQoKbGVnZW5kKCJib3R0b21yaWdodCIsIAogICAgICAgICAgbGVnZW5kID0gYygiaW5zdGFudGFuZW91cyBpbnRlcmFjdGlvbiBzdHJlbmd0aCIsICJjdW11bGF0aXZlIGludGVyYWN0aW9uIHN0cmVuZ3RoIiksICAKICAgICAgICAgIGNvbCA9IGMoImJsYWNrIiwgIiNmZjRiMDAiKSwgCiAgICAgICAgICBsdHkgPSBjKDEsIDIpLCAgICAgICAgICAgICAgCiAgICAgICAgICBjZXggPSBjKDAuOCkKKQpkZXYub2ZmKCkKCnBkZigiZmlnNGIucGRmIiwgd2lkdGggPSA0LCBoZWlnaHQgPSA0KQpwbG90KHJrNF9yZXN1bHQkdFsxMDE6MTgxXSwgdGF1MypkQzFkQzEocms0X3Jlc3VsdClbMTAxOjE4MV0sIHR5cGUgPSAibCIsIGNvbCA9ICJibGFjayIsIHlsaW0gPSBjKC0wLjQsIDAuMyksIHhsYWIgPSAidGltZSIsIHlsYWIgPSAiSW50ZXJhY3Rpb24gc3RyZW5ndGhzIEMxIC0+IEMxIiwgbHdkID0gMSwgbWFpbiA9IGV4cHJlc3Npb24ocGFzdGUodGF1LCAiPSAwLjUiLCBzZXA9IiIpKSkKcGFyKG5ldyA9IFQpCnBsb3Qocms0X3Jlc3VsdCR0WzEwMToxODFdLCBwcmVjaXNlX2RhdGEkdGF1MC41X3ByZWNpc2VfZEMxZEMxWzEwMToxODFdLCB0eXBlID0gImwiLCBjb2wgPSAiI2ZmNGIwMCIsIGx3ZCA9IDIsIGx0eSA9IDIsIHlsaW0gPSBjKC0wLjQsIDAuMyksIHhsYWIgPSAiIiwgeWxhYiA9ICIiKQpkZXYub2ZmKCkKCnBkZigiZmlnNGMucGRmIiwgd2lkdGggPSA0LCBoZWlnaHQgPSA0KQpwbG90KHJrNF9yZXN1bHQkdFsxMDE6MTgxXSwgdGF1NCpkQzFkQzEocms0X3Jlc3VsdClbMTAxOjE4MV0sIHR5cGUgPSAibCIsIGNvbCA9ICJibGFjayIsIHlsaW0gPSBjKDAuMCwgMC4xNSksIHhsYWIgPSAidGltZSIsIHlsYWIgPSAiSW50ZXJhY3Rpb24gc3RyZW5ndGhzIEMxIC0+IEMxIiwgbHdkID0gMSwgbWFpbiA9IGV4cHJlc3Npb24ocGFzdGUodGF1LCAiPSAxLjAiLCBzZXA9IiIpKSkKcGFyKG5ldyA9IFQpCnBsb3Qocms0X3Jlc3VsdCR0WzEwMToxODFdLCBwcmVjaXNlX2RhdGEkdGF1MS4wX3ByZWNpc2VfZEMxZEMxWzEwMToxODFdLCB0eXBlID0gImwiLCBjb2wgPSAiI2ZmNGIwMCIsIGx3ZCA9IDIsIGx0eSA9IDIsIHlsaW0gPSBjKDAuMCwgMC4xNSksIHhsYWIgPSAiIiwgeWxhYiA9ICIiKQpkZXYub2ZmKCkKCnBkZigiZmlnNGQucGRmIiwgd2lkdGggPSA0LCBoZWlnaHQgPSA0KQpwbG90KHJrNF9yZXN1bHQkdFsxMDE6MTgxXSwgdGF1NSpkQzFkQzEocms0X3Jlc3VsdClbMTAxOjE4MV0sIHR5cGUgPSAibCIsIGNvbCA9ICJibGFjayIsIHlsaW0gPSBjKC0wLjQsIDAuMyksIHhsYWIgPSAidGltZSIsIHlsYWIgPSAiSW50ZXJhY3Rpb24gc3RyZW5ndGhzIEMxIC0+IEMxIiwgbHdkID0gMSwgbWFpbiA9IGV4cHJlc3Npb24ocGFzdGUodGF1LCAiPSAyLjAiLCBzZXA9IiIpKSkKcGFyKG5ldyA9IFQpCnBsb3Qocms0X3Jlc3VsdCR0WzEwMToxODFdLCBwcmVjaXNlX2RhdGEkdGF1Mi4wX3ByZWNpc2VfZEMxZEMxWzEwMToxODFdLCB0eXBlID0gImwiLCBjb2wgPSAiI2ZmNGIwMCIsIGx3ZCA9IDIsIGx0eSA9IDIsIHlsaW0gPSBjKC0wLjQsIDAuMyksIHhsYWIgPSAiIiwgeWxhYiA9ICIiKQpkZXYub2ZmKCkKCnBkZigiZmlnNGUucGRmIiwgd2lkdGggPSA0LCBoZWlnaHQgPSA0KQpwbG90KHJrNF9yZXN1bHQkdFsxMDE6MTgxXSwgdGF1MSpkQzFkQzEocms0X3Jlc3VsdClbMTAxOjE4MV0sIHR5cGUgPSAibCIsIGNvbCA9ICJibGFjayIsIHlsaW0gPSBjKC0yLCAyKSwgeGxhYiA9ICJ0aW1lIiwgeWxhYiA9ICJJbnRlcmFjdGlvbiBzdHJlbmd0aHMgQzEgLT4gQzEiLCBsd2QgPSAxLCBtYWluID0gZXhwcmVzc2lvbihwYXN0ZSh0YXUsICI9IDUuMCIsIHNlcD0iIikpKQpwYXIobmV3ID0gVCkKcGxvdChyazRfcmVzdWx0JHRbMTAxOjE4MV0sIHByZWNpc2VfZGF0YSRwcmVjaXNlX2RDMWRDMVsxMDE6MTgxXSwgdHlwZSA9ICJsIiwgY29sID0gIiNmZjRiMDAiLCBsd2QgPSAyLCBsdHkgPSAyLCB5bGltID0gYygtMiwgMiksIHhsYWIgPSAiIiwgeWxhYiA9ICIiKQpkZXYub2ZmKCkKCnBkZigiZmlnNGYucGRmIiwgd2lkdGggPSA0LCBoZWlnaHQgPSA0KQpwbG90KHJrNF9yZXN1bHQkdFsxMDE6MTgxXSwgdGF1NipkQzFkQzEocms0X3Jlc3VsdClbMTAxOjE4MV0sIHR5cGUgPSAibCIsIGNvbCA9ICJibGFjayIsIHlsaW0gPSBjKC0yLCAzKSwgeGxhYiA9ICJ0aW1lIiwgeWxhYiA9ICJJbnRlcmFjdGlvbiBzdHJlbmd0aHMgQzEgLT4gQzEiLCBsd2QgPSAxLCBtYWluID0gZXhwcmVzc2lvbihwYXN0ZSh0YXUsICI9IDEwLjAiLCBzZXA9IiIpKSkKcGFyKG5ldyA9IFQpCnBsb3Qocms0X3Jlc3VsdCR0WzEwMToxODFdLCBwcmVjaXNlX2RhdGEkdGF1MTAuMF9wcmVjaXNlX2RDMWRDMVsxMDE6MTgxXSwgdHlwZSA9ICJsIiwgY29sID0gIiNmZjRiMDAiLCBsd2QgPSAyLCBsdHkgPSAyLCB5bGltID0gYygtMiwgMyksIHhsYWIgPSAiIiwgeWxhYiA9ICIiKQpkZXYub2ZmKCkKYGBgCgoKCgo=